mirror of https://gitee.com/openkylin/linux.git
- Core Frameworks
- Standardise MFD_CELL_* helpers - New Drivers - Add support for Acer Iconia Tab A500 Embedded Controller - New Device Support - Add support for ROHM BD9574MWF to BD9571MWV - Add support for Intel Alder Lake PCH-P PCI to LPSS - Add support for Intel Alder Lake PCH-S PCI to LPSS - New Functionality - Support ACPI enumeration; arizona - Fix-ups - Managed resources; bd9571mwv - DT additions/fix-ups; bd9571mwv, iqs62x, max8997, gateworks-gsc, ene-kb930 - Convert to SPDX; bd9571mw - Fix return values/error handling; sunxi - Provide SOFTDEP; arizona - Make use of DIV_ROUND_UP; mcp-sa11x0 - Use generic APIs; arizona - Add MAC address sysfs entries; intel-m10-bmc - Trivial: Coding-style fix-ups; iqs62x - Trivial: Remove superflouous code; iqs62x - Clear-up naming conventions; iqs62x - Bug Fixes - Fix 'pointer from integer' error; altera-sysmgr - Convert SGI_MFD_IOC3 from tristate to bool; Kconfig - Fix interrupt handling; gateworks-gsc - Extend required delay; iqs62x - Do not use I2C polling during calibration; iqs62x - Do no adjust clock frequency during calibration; iqs62x - Fix use-after-free; wm831x-auxad -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmAr4agACgkQUa+KL4f8 d2GcqhAAkfGRWU7RVWlOK2NcYIDGiSU5kAJgirwIpDxkZM+kNjYITm+jt5JYBdIc B1ShJSgc3kgcs62nTUTqkGjL6IQyI6aPsI4oF57XnN6nmIGzSQ84cCSbBn7eXUIP wF2/4V0L+eE7i6TaZNcyZ4EltkKvo06MCs35eUATyFLB/9ZfhBCRjQlk5z4YOG6n Mc3VJiLSpNv8PWTL+tw76RMk8mScUFaKwra8fYK4OVG/zjJ43tsADu4G6gF7FkZE Erlp+fvFFmSR5STEri8cY0AFjHYHGWrST7lQ0HUsgM72A+TjFsy2X6WsDZzwVp+Z Ymk0T4NAQWJ/QBu2kwws0L2EieYTtzY1DjKJV6MIiwp1OWIK+TQGV9zPgkXFq404 Rcw6LZjkEgeMJFx/4ljK5xC/y6CKGguxrXCYDVj0aeU+OcC1nnjx9KJwYWCsfwWU 0QUIPK0Fy0m2L0Jy/MeDakHtdkPzBLWOe5ybE9EmY8EV+RUorH6bEWVA6cmsJNgq ycUlx8hK0nO+yIOMFua8Tk4+0gpcS9QrSGNoz3Iw/sZa6knX4vyvHxyebu/91qas VwnU//s8LzpeiYu8hsjlbZsZTlP4Gnc2QhaWW757hTwykwMjhlHLAo/CZ85LVzCg mmd1xybdMsQFAAoemp6D1HixLG/cMP5bflqCB+hZ8SUhHOiPZNU= =ieAS -----END PGP SIGNATURE----- Merge tag 'mfd-next-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd Pull MFD updates from Lee Jones: "Core Frameworks: - Standardise MFD_CELL_* helpers New Drivers: - Add support for Acer Iconia Tab A500 Embedded Controller New Device Support: - Add support for ROHM BD9574MWF to BD9571MWV - Add support for Intel Alder Lake PCH-P PCI to LPSS - Add support for Intel Alder Lake PCH-S PCI to LPSS New Functionality: - Support ACPI enumeration; arizona Fix-ups: - Managed resources; bd9571mwv - DT additions/fix-ups; bd9571mwv, iqs62x, max8997, gateworks-gsc, ene-kb930 - Convert to SPDX; bd9571mw - Fix return values/error handling; sunxi - Provide SOFTDEP; arizona - Make use of DIV_ROUND_UP; mcp-sa11x0 - Use generic APIs; arizona - Add MAC address sysfs entries; intel-m10-bmc - Trivial: Coding-style fix-ups; iqs62x - Trivial: Remove superflouous code; iqs62x - Clear-up naming conventions; iqs62x Bug Fixes: - Fix 'pointer from integer' error; altera-sysmgr - Convert SGI_MFD_IOC3 from tristate to bool; Kconfig - Fix interrupt handling; gateworks-gsc - Extend required delay; iqs62x - Do not use I2C polling during calibration; iqs62x - Do no adjust clock frequency during calibration; iqs62x - Fix use-after-free; wm831x-auxad" * tag 'mfd-next-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (32 commits) mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq() mfd: iqs62x: Do not change clock frequency during ATI mfd: iqs62x: Do not poll during ATI mfd: iqs62x: Increase interrupt handler return delay mfd: iqs62x: Rename regmap_config struct mfd: iqs62x: Remove unused bit mask mfd: iqs62x: Remove superfluous whitespace above fallthroughs mfd: intel-lpss: Add Intel Alder Lake PCH-S PCI IDs mfd: intel-m10-bmc: Expose MAC address and count mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500 dt-bindings: mfd: Add ENE KB930 Embedded Controller binding dt-bindings: mfd: gateworks-gsc: Add fan-tach mode mfd: intel-lpss: Add Intel Alder Lake PCH-P PCI IDs mfd: gateworks-gsc: Fix interrupt type mfd: Standardise MFD_CELL_* helper names mfd: mcp-sa11x0: Use DIV_ROUND_UP to calculate rw_timeout mfd: max8997: Add of_compatible to Extcon and Charger mfd_cell dt-bindings: mfd: Correct the node name of the panel LED mfd: sgi-ioc3: Turn Kconfig option into a bool mfd: altera-sysmgr: Fix physical address storing more ...
This commit is contained in:
commit
f158bbee94
|
@ -13,3 +13,24 @@ Contact: Xu Yilun <yilun.xu@intel.com>
|
|||
Description: Read only. Returns the firmware version of Intel MAX10
|
||||
BMC chip.
|
||||
Format: "0x%x".
|
||||
|
||||
What: /sys/bus/spi/devices/.../mac_address
|
||||
Date: January 2021
|
||||
KernelVersion: 5.12
|
||||
Contact: Russ Weight <russell.h.weight@intel.com>
|
||||
Description: Read only. Returns the first MAC address in a block
|
||||
of sequential MAC addresses assigned to the board
|
||||
that is managed by the Intel MAX10 BMC. It is stored in
|
||||
FLASH storage and is mirrored in the MAX10 BMC register
|
||||
space.
|
||||
Format: "%02x:%02x:%02x:%02x:%02x:%02x".
|
||||
|
||||
What: /sys/bus/spi/devices/.../mac_count
|
||||
Date: January 2021
|
||||
KernelVersion: 5.12
|
||||
Contact: Russ Weight <russell.h.weight@intel.com>
|
||||
Description: Read only. Returns the number of sequential MAC
|
||||
addresses assigned to the board managed by the Intel
|
||||
MAX10 BMC. This value is stored in FLASH and is mirrored
|
||||
in the MAX10 BMC register space.
|
||||
Format: "%u".
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
* ROHM BD9571MWV Power Management Integrated Circuit (PMIC) bindings
|
||||
* ROHM BD9571MWV/BD9574MWF Power Management Integrated Circuit (PMIC) bindings
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "rohm,bd9571mwv".
|
||||
- compatible : Should be "rohm,bd9571mwv" or "rohm,bd9574mwf".
|
||||
- reg : I2C slave address.
|
||||
- interrupts : The interrupt line the device is connected to.
|
||||
- interrupt-controller : Marks the device node as an interrupt controller.
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/ene-kb930.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ENE KB930 Embedded Controller bindings
|
||||
|
||||
description: |
|
||||
This binding describes the ENE KB930 Embedded Controller attached to an
|
||||
I2C bus.
|
||||
|
||||
maintainers:
|
||||
- Dmitry Osipenko <digetx@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- acer,a500-iconia-ec # Acer A500 Iconia tablet device
|
||||
- const: ene,kb930
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
monitored-battery: true
|
||||
power-supplies: true
|
||||
system-power-controller: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
battery: battery-cell {
|
||||
compatible = "simple-battery";
|
||||
charge-full-design-microamp-hours = <3260000>;
|
||||
energy-full-design-microwatt-hours = <24000000>;
|
||||
operating-range-celsius = <0 40>;
|
||||
};
|
||||
|
||||
mains: ac-adapter {
|
||||
compatible = "gpio-charger";
|
||||
charger-type = "mains";
|
||||
gpios = <&gpio 125 0>;
|
||||
};
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
embedded-controller@58 {
|
||||
compatible = "acer,a500-iconia-ec", "ene,kb930";
|
||||
reg = <0x58>;
|
||||
|
||||
system-power-controller;
|
||||
|
||||
monitored-battery = <&battery>;
|
||||
power-supplies = <&mains>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -83,8 +83,9 @@ properties:
|
|||
2 - scaled voltage based on an optional resistor divider
|
||||
and optional offset
|
||||
3 - pre-scaled 16-bit voltage value
|
||||
4 - fan tach input to report RPM's
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3]
|
||||
enum: [0, 1, 2, 3, 4]
|
||||
|
||||
gw,voltage-divider-ohms:
|
||||
description: Values of resistors for divider on raw ADC input
|
||||
|
|
|
@ -93,7 +93,7 @@ examples:
|
|||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
|
||||
panel {
|
||||
led-1 {
|
||||
pwms = <&iqs620a_pwm 0 1000000>;
|
||||
max-brightness = <255>;
|
||||
};
|
||||
|
|
|
@ -1,31 +1,24 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ROHM BD9571MWV-M GPIO driver
|
||||
* ROHM BD9571MWV-M and BD9574MWF-M GPIO driver
|
||||
*
|
||||
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether expressed or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License version 2 for more details.
|
||||
*
|
||||
* Based on the TPS65086 driver
|
||||
*
|
||||
* NOTE: Interrupts are not supported yet.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/mfd/bd9571mwv.h>
|
||||
|
||||
struct bd9571mwv_gpio {
|
||||
struct regmap *regmap;
|
||||
struct gpio_chip chip;
|
||||
struct bd9571mwv *bd;
|
||||
};
|
||||
|
||||
static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
|
||||
|
@ -34,7 +27,7 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
|
|||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val);
|
||||
ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_DIR, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (val & BIT(offset))
|
||||
|
@ -48,8 +41,7 @@ static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip,
|
|||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
|
||||
BIT(offset), 0);
|
||||
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR, BIT(offset), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,9 +52,9 @@ static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip,
|
|||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
/* Set the initial value */
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
|
||||
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT,
|
||||
BIT(offset), value ? BIT(offset) : 0);
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
|
||||
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR,
|
||||
BIT(offset), BIT(offset));
|
||||
|
||||
return 0;
|
||||
|
@ -73,7 +65,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
|||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val);
|
||||
ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_IN, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -85,7 +77,7 @@ static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
|||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
|
||||
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT,
|
||||
BIT(offset), value ? BIT(offset) : 0);
|
||||
}
|
||||
|
||||
|
@ -113,9 +105,9 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
gpio->bd = dev_get_drvdata(pdev->dev.parent);
|
||||
gpio->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
gpio->chip = template_chip;
|
||||
gpio->chip.parent = gpio->bd->dev;
|
||||
gpio->chip.parent = pdev->dev.parent;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||
if (ret < 0) {
|
||||
|
@ -127,7 +119,8 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
|
||||
{ "bd9571mwv-gpio", },
|
||||
{ "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 },
|
||||
{ "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
|
||||
|
|
|
@ -2085,6 +2085,17 @@ config MFD_KHADAS_MCU
|
|||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
config MFD_ACER_A500_EC
|
||||
tristate "Support for Acer Iconia Tab A500 Embedded Controller"
|
||||
depends on I2C
|
||||
depends on (ARCH_TEGRA_2x_SOC && OF) || COMPILE_TEST
|
||||
select MFD_CORE
|
||||
select REGMAP
|
||||
help
|
||||
Support for Embedded Controller found on Acer Iconia Tab A500.
|
||||
The controller itself is ENE KB930, it is running firmware
|
||||
customized for the specific needs of the Acer A500 hardware.
|
||||
|
||||
menu "Multimedia Capabilities Port drivers"
|
||||
depends on ARCH_SA1100
|
||||
|
||||
|
@ -2129,7 +2140,7 @@ config RAVE_SP_CORE
|
|||
device found on several devices in RAVE line of hardware.
|
||||
|
||||
config SGI_MFD_IOC3
|
||||
tristate "SGI IOC3 core driver"
|
||||
bool "SGI IOC3 core driver"
|
||||
depends on PCI && MIPS && 64BIT
|
||||
select MFD_CORE
|
||||
help
|
||||
|
|
|
@ -264,6 +264,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o
|
|||
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
|
||||
obj-$(CONFIG_MFD_STMFX) += stmfx.o
|
||||
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
|
||||
obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
|
||||
|
||||
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
|
||||
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
|
||||
|
|
|
@ -609,52 +609,52 @@ int ab8500_suspend(struct ab8500 *ab8500)
|
|||
}
|
||||
|
||||
static const struct mfd_cell ab8500_bm_devs[] = {
|
||||
OF_MFD_CELL("ab8500-charger", NULL, &ab8500_bm_data,
|
||||
MFD_CELL_OF("ab8500-charger", NULL, &ab8500_bm_data,
|
||||
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"),
|
||||
OF_MFD_CELL("ab8500-btemp", NULL, &ab8500_bm_data,
|
||||
MFD_CELL_OF("ab8500-btemp", NULL, &ab8500_bm_data,
|
||||
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"),
|
||||
OF_MFD_CELL("ab8500-fg", NULL, &ab8500_bm_data,
|
||||
MFD_CELL_OF("ab8500-fg", NULL, &ab8500_bm_data,
|
||||
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"),
|
||||
OF_MFD_CELL("ab8500-chargalg", NULL, &ab8500_bm_data,
|
||||
MFD_CELL_OF("ab8500-chargalg", NULL, &ab8500_bm_data,
|
||||
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"),
|
||||
};
|
||||
|
||||
static const struct mfd_cell ab8500_devs[] = {
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
OF_MFD_CELL("ab8500-debug",
|
||||
MFD_CELL_OF("ab8500-debug",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-debug"),
|
||||
#endif
|
||||
OF_MFD_CELL("ab8500-sysctrl",
|
||||
MFD_CELL_OF("ab8500-sysctrl",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"),
|
||||
OF_MFD_CELL("ab8500-ext-regulator",
|
||||
MFD_CELL_OF("ab8500-ext-regulator",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"),
|
||||
OF_MFD_CELL("ab8500-regulator",
|
||||
MFD_CELL_OF("ab8500-regulator",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-regulator"),
|
||||
OF_MFD_CELL("ab8500-clk",
|
||||
MFD_CELL_OF("ab8500-clk",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-clk"),
|
||||
OF_MFD_CELL("ab8500-gpadc",
|
||||
MFD_CELL_OF("ab8500-gpadc",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"),
|
||||
OF_MFD_CELL("ab8500-rtc",
|
||||
MFD_CELL_OF("ab8500-rtc",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-rtc"),
|
||||
OF_MFD_CELL("ab8500-acc-det",
|
||||
MFD_CELL_OF("ab8500-acc-det",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"),
|
||||
OF_MFD_CELL("ab8500-poweron-key",
|
||||
MFD_CELL_OF("ab8500-poweron-key",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"),
|
||||
OF_MFD_CELL("ab8500-pwm",
|
||||
MFD_CELL_OF("ab8500-pwm",
|
||||
NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
|
||||
OF_MFD_CELL("ab8500-pwm",
|
||||
MFD_CELL_OF("ab8500-pwm",
|
||||
NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
|
||||
OF_MFD_CELL("ab8500-pwm",
|
||||
MFD_CELL_OF("ab8500-pwm",
|
||||
NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
|
||||
OF_MFD_CELL("ab8500-denc",
|
||||
MFD_CELL_OF("ab8500-denc",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-denc"),
|
||||
OF_MFD_CELL("pinctrl-ab8500",
|
||||
MFD_CELL_OF("pinctrl-ab8500",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-gpio"),
|
||||
OF_MFD_CELL("abx500-temp",
|
||||
MFD_CELL_OF("abx500-temp",
|
||||
NULL, NULL, 0, 0, "stericsson,abx500-temp"),
|
||||
OF_MFD_CELL("ab8500-usb",
|
||||
MFD_CELL_OF("ab8500-usb",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-usb"),
|
||||
OF_MFD_CELL("ab8500-codec",
|
||||
MFD_CELL_OF("ab8500-codec",
|
||||
NULL, NULL, 0, 0, "stericsson,ab8500-codec"),
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Acer Iconia Tab A500 Embedded Controller Driver
|
||||
*
|
||||
* Copyright 2020 GRATE-driver project
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define A500_EC_I2C_ERR_TIMEOUT 500
|
||||
#define A500_EC_POWER_CMD_TIMEOUT 1000
|
||||
|
||||
/*
|
||||
* Controller's firmware expects specific command opcodes to be used for the
|
||||
* corresponding registers. Unsupported commands are skipped by the firmware.
|
||||
*/
|
||||
#define CMD_SHUTDOWN 0x0
|
||||
#define CMD_WARM_REBOOT 0x0
|
||||
#define CMD_COLD_REBOOT 0x1
|
||||
|
||||
enum {
|
||||
REG_CURRENT_NOW = 0x03,
|
||||
REG_SHUTDOWN = 0x52,
|
||||
REG_WARM_REBOOT = 0x54,
|
||||
REG_COLD_REBOOT = 0x55,
|
||||
};
|
||||
|
||||
static struct i2c_client *a500_ec_client_pm_off;
|
||||
|
||||
static int a500_ec_read(void *context, const void *reg_buf, size_t reg_size,
|
||||
void *val_buf, size_t val_sizel)
|
||||
{
|
||||
struct i2c_client *client = context;
|
||||
unsigned int reg, retries = 5;
|
||||
u16 *ret_val = val_buf;
|
||||
s32 ret = 0;
|
||||
|
||||
reg = *(u8 *)reg_buf;
|
||||
|
||||
while (retries-- > 0) {
|
||||
ret = i2c_smbus_read_word_data(client, reg);
|
||||
if (ret >= 0)
|
||||
break;
|
||||
|
||||
msleep(A500_EC_I2C_ERR_TIMEOUT);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "read 0x%x failed: %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*ret_val = ret;
|
||||
|
||||
if (reg == REG_CURRENT_NOW)
|
||||
fsleep(10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a500_ec_write(void *context, const void *data, size_t count)
|
||||
{
|
||||
struct i2c_client *client = context;
|
||||
unsigned int reg, val, retries = 5;
|
||||
s32 ret = 0;
|
||||
|
||||
reg = *(u8 *)(data + 0);
|
||||
val = *(u16 *)(data + 1);
|
||||
|
||||
while (retries-- > 0) {
|
||||
ret = i2c_smbus_write_word_data(client, reg, val);
|
||||
if (ret >= 0)
|
||||
break;
|
||||
|
||||
msleep(A500_EC_I2C_ERR_TIMEOUT);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "write 0x%x failed: %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config a500_ec_regmap_config = {
|
||||
.name = "KB930",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = 0xff,
|
||||
};
|
||||
|
||||
static const struct regmap_bus a500_ec_regmap_bus = {
|
||||
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
|
||||
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
|
||||
.write = a500_ec_write,
|
||||
.read = a500_ec_read,
|
||||
.max_raw_read = 2,
|
||||
};
|
||||
|
||||
static void a500_ec_poweroff(void)
|
||||
{
|
||||
i2c_smbus_write_word_data(a500_ec_client_pm_off,
|
||||
REG_SHUTDOWN, CMD_SHUTDOWN);
|
||||
|
||||
mdelay(A500_EC_POWER_CMD_TIMEOUT);
|
||||
}
|
||||
|
||||
static int a500_ec_restart_notify(struct notifier_block *this,
|
||||
unsigned long reboot_mode, void *data)
|
||||
{
|
||||
if (reboot_mode == REBOOT_WARM)
|
||||
i2c_smbus_write_word_data(a500_ec_client_pm_off,
|
||||
REG_WARM_REBOOT, CMD_WARM_REBOOT);
|
||||
else
|
||||
i2c_smbus_write_word_data(a500_ec_client_pm_off,
|
||||
REG_COLD_REBOOT, CMD_COLD_REBOOT);
|
||||
|
||||
mdelay(A500_EC_POWER_CMD_TIMEOUT);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block a500_ec_restart_handler = {
|
||||
.notifier_call = a500_ec_restart_notify,
|
||||
.priority = 200,
|
||||
};
|
||||
|
||||
static const struct mfd_cell a500_ec_cells[] = {
|
||||
{ .name = "acer-a500-iconia-battery", },
|
||||
{ .name = "acer-a500-iconia-leds", },
|
||||
};
|
||||
|
||||
static int a500_ec_probe(struct i2c_client *client)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
int err;
|
||||
|
||||
regmap = devm_regmap_init(&client->dev, &a500_ec_regmap_bus,
|
||||
client, &a500_ec_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
err = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
|
||||
a500_ec_cells, ARRAY_SIZE(a500_ec_cells),
|
||||
NULL, 0, NULL);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "failed to add sub-devices: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (of_device_is_system_power_controller(client->dev.of_node)) {
|
||||
a500_ec_client_pm_off = client;
|
||||
|
||||
err = register_restart_handler(&a500_ec_restart_handler);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!pm_power_off)
|
||||
pm_power_off = a500_ec_poweroff;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a500_ec_remove(struct i2c_client *client)
|
||||
{
|
||||
if (of_device_is_system_power_controller(client->dev.of_node)) {
|
||||
if (pm_power_off == a500_ec_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
unregister_restart_handler(&a500_ec_restart_handler);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id a500_ec_match[] = {
|
||||
{ .compatible = "acer,a500-iconia-ec" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, a500_ec_match);
|
||||
|
||||
static struct i2c_driver a500_ec_driver = {
|
||||
.driver = {
|
||||
.name = "acer-a500-embedded-controller",
|
||||
.of_match_table = a500_ec_match,
|
||||
},
|
||||
.probe_new = a500_ec_probe,
|
||||
.remove = a500_ec_remove,
|
||||
};
|
||||
module_i2c_driver(a500_ec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Acer Iconia Tab A500 Embedded Controller driver");
|
||||
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -145,7 +145,8 @@ static int sysmgr_probe(struct platform_device *pdev)
|
|||
sysmgr_config.reg_write = s10_protected_reg_write;
|
||||
|
||||
/* Need physical address for SMCC call */
|
||||
regmap = devm_regmap_init(dev, NULL, (void *)res->start,
|
||||
regmap = devm_regmap_init(dev, NULL,
|
||||
(void *)(uintptr_t)res->start,
|
||||
&sysmgr_config);
|
||||
} else {
|
||||
base = devm_ioremap(dev, res->start, resource_size(res));
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ROHM BD9571MWV-M MFD driver
|
||||
* ROHM BD9571MWV-M and BD9574MVF-M core driver
|
||||
*
|
||||
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether expressed or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License version 2 for more details.
|
||||
* Copyright (C) 2020 Renesas Electronics Corporation
|
||||
*
|
||||
* Based on the TPS65086 driver
|
||||
*/
|
||||
|
@ -18,6 +11,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/mfd/bd9571mwv.h>
|
||||
|
@ -110,13 +104,78 @@ static struct regmap_irq_chip bd9571mwv_irq_chip = {
|
|||
.num_irqs = ARRAY_SIZE(bd9571mwv_irqs),
|
||||
};
|
||||
|
||||
static int bd9571mwv_identify(struct bd9571mwv *bd)
|
||||
static const struct mfd_cell bd9574mwf_cells[] = {
|
||||
{ .name = "bd9574mwf-regulator", },
|
||||
{ .name = "bd9574mwf-gpio", },
|
||||
};
|
||||
|
||||
static const struct regmap_range bd9574mwf_readable_yes_ranges[] = {
|
||||
regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION),
|
||||
regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
|
||||
regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_SETVMAX),
|
||||
regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_MONIVDAC),
|
||||
regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
|
||||
regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK),
|
||||
regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd9574mwf_readable_table = {
|
||||
.yes_ranges = bd9574mwf_readable_yes_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(bd9574mwf_readable_yes_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range bd9574mwf_writable_yes_ranges[] = {
|
||||
regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
|
||||
regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID),
|
||||
regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT),
|
||||
regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK),
|
||||
regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd9574mwf_writable_table = {
|
||||
.yes_ranges = bd9574mwf_writable_yes_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(bd9574mwf_writable_yes_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range bd9574mwf_volatile_yes_ranges[] = {
|
||||
regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC),
|
||||
regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
|
||||
regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT),
|
||||
regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd9574mwf_volatile_table = {
|
||||
.yes_ranges = bd9574mwf_volatile_yes_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(bd9574mwf_volatile_yes_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config bd9574mwf_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.rd_table = &bd9574mwf_readable_table,
|
||||
.wr_table = &bd9574mwf_writable_table,
|
||||
.volatile_table = &bd9574mwf_volatile_table,
|
||||
.max_register = 0xff,
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip bd9574mwf_irq_chip = {
|
||||
.name = "bd9574mwf",
|
||||
.status_base = BD9571MWV_INT_INTREQ,
|
||||
.mask_base = BD9571MWV_INT_INTMASK,
|
||||
.ack_base = BD9571MWV_INT_INTREQ,
|
||||
.init_ack_masked = true,
|
||||
.num_regs = 1,
|
||||
.irqs = bd9571mwv_irqs,
|
||||
.num_irqs = ARRAY_SIZE(bd9571mwv_irqs),
|
||||
};
|
||||
|
||||
static int bd957x_identify(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct device *dev = bd->dev;
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value);
|
||||
ret = regmap_read(regmap, BD9571MWV_VENDOR_CODE, &value);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read vendor code register (ret=%i)\n",
|
||||
ret);
|
||||
|
@ -129,84 +188,82 @@ static int bd9571mwv_identify(struct bd9571mwv *bd)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value);
|
||||
ret = regmap_read(regmap, BD9571MWV_PRODUCT_CODE, &value);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read product code register (ret=%i)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (value != BD9571MWV_PRODUCT_CODE_VAL) {
|
||||
dev_err(dev, "Invalid product code ID %02x (expected %02x)\n",
|
||||
value, BD9571MWV_PRODUCT_CODE_VAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value);
|
||||
ret = regmap_read(regmap, BD9571MWV_PRODUCT_REVISION, &value);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read revision register (ret=%i)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd9571mwv_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *ids)
|
||||
const struct i2c_device_id *ids)
|
||||
{
|
||||
struct bd9571mwv *bd;
|
||||
int ret;
|
||||
const struct regmap_config *regmap_config;
|
||||
const struct regmap_irq_chip *irq_chip;
|
||||
const struct mfd_cell *cells;
|
||||
struct device *dev = &client->dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
int ret, num_cells, irq = client->irq;
|
||||
|
||||
bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL);
|
||||
if (!bd)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, bd);
|
||||
bd->dev = &client->dev;
|
||||
bd->irq = client->irq;
|
||||
|
||||
bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config);
|
||||
if (IS_ERR(bd->regmap)) {
|
||||
dev_err(bd->dev, "Failed to initialize register map\n");
|
||||
return PTR_ERR(bd->regmap);
|
||||
/* Read the PMIC product code */
|
||||
ret = i2c_smbus_read_byte_data(client, BD9571MWV_PRODUCT_CODE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read product code\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bd9571mwv_identify(bd);
|
||||
switch (ret) {
|
||||
case BD9571MWV_PRODUCT_CODE_BD9571MWV:
|
||||
regmap_config = &bd9571mwv_regmap_config;
|
||||
irq_chip = &bd9571mwv_irq_chip;
|
||||
cells = bd9571mwv_cells;
|
||||
num_cells = ARRAY_SIZE(bd9571mwv_cells);
|
||||
break;
|
||||
case BD9571MWV_PRODUCT_CODE_BD9574MWF:
|
||||
regmap_config = &bd9574mwf_regmap_config;
|
||||
irq_chip = &bd9574mwf_irq_chip;
|
||||
cells = bd9574mwf_cells;
|
||||
num_cells = ARRAY_SIZE(bd9574mwf_cells);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unsupported device 0x%x\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "Failed to initialize register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
ret = bd957x_identify(dev, regmap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_add_irq_chip(bd->regmap, bd->irq, IRQF_ONESHOT, 0,
|
||||
&bd9571mwv_irq_chip, &bd->irq_data);
|
||||
ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0,
|
||||
irq_chip, &irq_data);
|
||||
if (ret) {
|
||||
dev_err(bd->dev, "Failed to register IRQ chip\n");
|
||||
dev_err(dev, "Failed to register IRQ chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells,
|
||||
ARRAY_SIZE(bd9571mwv_cells), NULL, 0,
|
||||
regmap_irq_get_domain(bd->irq_data));
|
||||
if (ret) {
|
||||
regmap_del_irq_chip(bd->irq, bd->irq_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd9571mwv_remove(struct i2c_client *client)
|
||||
{
|
||||
struct bd9571mwv *bd = i2c_get_clientdata(client);
|
||||
|
||||
regmap_del_irq_chip(bd->irq, bd->irq_data);
|
||||
|
||||
return 0;
|
||||
return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, num_cells,
|
||||
NULL, 0, regmap_irq_get_domain(irq_data));
|
||||
}
|
||||
|
||||
static const struct of_device_id bd9571mwv_of_match_table[] = {
|
||||
{ .compatible = "rohm,bd9571mwv", },
|
||||
{ .compatible = "rohm,bd9574mwf", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table);
|
||||
|
@ -223,7 +280,6 @@ static struct i2c_driver bd9571mwv_driver = {
|
|||
.of_match_table = bd9571mwv_of_match_table,
|
||||
},
|
||||
.probe = bd9571mwv_probe,
|
||||
.remove = bd9571mwv_remove,
|
||||
.id_table = bd9571mwv_id_table,
|
||||
};
|
||||
module_i2c_driver(bd9571mwv_driver);
|
||||
|
|
|
@ -2954,12 +2954,12 @@ static const struct mfd_cell common_prcmu_devs[] = {
|
|||
};
|
||||
|
||||
static const struct mfd_cell db8500_prcmu_devs[] = {
|
||||
OF_MFD_CELL("db8500-prcmu-regulators", NULL,
|
||||
MFD_CELL_OF("db8500-prcmu-regulators", NULL,
|
||||
&db8500_regulators, sizeof(db8500_regulators), 0,
|
||||
"stericsson,db8500-prcmu-regulator"),
|
||||
OF_MFD_CELL("cpuidle-dbx500",
|
||||
MFD_CELL_OF("cpuidle-dbx500",
|
||||
NULL, NULL, 0, 0, "stericsson,cpuidle-dbx500"),
|
||||
OF_MFD_CELL("db8500-thermal",
|
||||
MFD_CELL_OF("db8500-thermal",
|
||||
NULL, NULL, 0, 0, "stericsson,db8500-thermal"),
|
||||
};
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ static int gsc_probe(struct i2c_client *client)
|
|||
|
||||
ret = devm_regmap_add_irq_chip(dev, gsc->regmap, client->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED |
|
||||
IRQF_TRIGGER_FALLING, 0,
|
||||
IRQF_TRIGGER_LOW, 0,
|
||||
&gsc_irq_chip, &irq_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -277,6 +277,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x4dea), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x4deb), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&spt_info },
|
||||
/* ADL-P */
|
||||
{ PCI_VDEVICE(INTEL, 0x51a8), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51a9), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51c5), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51c6), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51c7), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51e8), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51e9), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&bxt_info },
|
||||
/* APL */
|
||||
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
|
||||
|
@ -293,6 +306,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info },
|
||||
/* ADL-S */
|
||||
{ PCI_VDEVICE(INTEL, 0x7aa8), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7aa9), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7acc), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7acd), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7ace), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7acf), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7adc), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7afc), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7afd), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7afe), (kernel_ulong_t)&bxt_uart_info },
|
||||
/* LKF */
|
||||
{ PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info },
|
||||
|
|
|
@ -60,9 +60,52 @@ static ssize_t bmcfw_version_show(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RO(bmcfw_version);
|
||||
|
||||
static ssize_t mac_address_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct intel_m10bmc *max10 = dev_get_drvdata(dev);
|
||||
unsigned int macaddr_low, macaddr_high;
|
||||
int ret;
|
||||
|
||||
ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
(u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low),
|
||||
(u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low),
|
||||
(u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low),
|
||||
(u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low),
|
||||
(u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high),
|
||||
(u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high));
|
||||
}
|
||||
static DEVICE_ATTR_RO(mac_address);
|
||||
|
||||
static ssize_t mac_count_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct intel_m10bmc *max10 = dev_get_drvdata(dev);
|
||||
unsigned int macaddr_high;
|
||||
int ret;
|
||||
|
||||
ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high));
|
||||
}
|
||||
static DEVICE_ATTR_RO(mac_count);
|
||||
|
||||
static struct attribute *m10bmc_attrs[] = {
|
||||
&dev_attr_bmc_version.attr,
|
||||
&dev_attr_bmcfw_version.attr,
|
||||
&dev_attr_mac_address.attr,
|
||||
&dev_attr_mac_count.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(m10bmc);
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#define IQS62X_PROD_NUM 0x00
|
||||
|
||||
#define IQS62X_SYS_FLAGS 0x10
|
||||
#define IQS62X_SYS_FLAGS_IN_ATI BIT(2)
|
||||
|
||||
#define IQS620_HALL_FLAGS 0x16
|
||||
#define IQS621_HALL_FLAGS 0x19
|
||||
|
@ -57,10 +56,10 @@
|
|||
#define IQS620_TEMP_CAL_OFFS 0xC4
|
||||
|
||||
#define IQS62X_SYS_SETTINGS 0xD0
|
||||
#define IQS62X_SYS_SETTINGS_SOFT_RESET BIT(7)
|
||||
#define IQS62X_SYS_SETTINGS_ACK_RESET BIT(6)
|
||||
#define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5)
|
||||
#define IQS62X_SYS_SETTINGS_CLK_DIV BIT(4)
|
||||
#define IQS62X_SYS_SETTINGS_COMM_ATI BIT(3)
|
||||
#define IQS62X_SYS_SETTINGS_REDO_ATI BIT(1)
|
||||
|
||||
#define IQS62X_PWR_SETTINGS 0xD2
|
||||
|
@ -82,9 +81,8 @@
|
|||
#define IQS62X_FW_REC_TYPE_MASK 3
|
||||
#define IQS62X_FW_REC_TYPE_DATA 4
|
||||
|
||||
#define IQS62X_ATI_POLL_SLEEP_US 10000
|
||||
#define IQS62X_ATI_POLL_TIMEOUT_US 500000
|
||||
#define IQS62X_ATI_STABLE_DELAY_MS 150
|
||||
#define IQS62X_ATI_STARTUP_MS 350
|
||||
#define IQS62X_FILT_SETTLE_MS 250
|
||||
|
||||
struct iqs62x_fw_rec {
|
||||
u8 type;
|
||||
|
@ -112,9 +110,16 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
|
|||
struct iqs62x_fw_blk *fw_blk;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
u8 clk_div = 1;
|
||||
|
||||
list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {
|
||||
/*
|
||||
* In case ATI is in progress, wait for it to complete before
|
||||
* lowering the core clock frequency.
|
||||
*/
|
||||
if (fw_blk->addr == IQS62X_SYS_SETTINGS &&
|
||||
*fw_blk->data & IQS62X_SYS_SETTINGS_CLK_DIV)
|
||||
msleep(IQS62X_ATI_STARTUP_MS);
|
||||
|
||||
if (fw_blk->mask)
|
||||
ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr,
|
||||
fw_blk->mask, *fw_blk->data);
|
||||
|
@ -135,7 +140,6 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
|
|||
|
||||
if (val & IQS620_PROX_SETTINGS_4_SAR_EN)
|
||||
iqs62x->ui_sel = IQS62X_UI_SAR1;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case IQS621_PROD_NUM:
|
||||
|
@ -183,28 +187,32 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(iqs62x->regmap, IQS62X_SYS_SETTINGS, &val);
|
||||
/*
|
||||
* Place the device in streaming mode at first so as not to miss the
|
||||
* limited number of interrupts that would otherwise occur after ATI
|
||||
* completes. The device is subsequently placed in event mode by the
|
||||
* interrupt handler.
|
||||
*
|
||||
* In the meantime, mask interrupts during ATI to prevent the device
|
||||
* from soliciting I2C traffic until the noise-sensitive ATI process
|
||||
* is complete.
|
||||
*/
|
||||
ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,
|
||||
IQS62X_SYS_SETTINGS_ACK_RESET |
|
||||
IQS62X_SYS_SETTINGS_EVENT_MODE |
|
||||
IQS62X_SYS_SETTINGS_COMM_ATI |
|
||||
IQS62X_SYS_SETTINGS_REDO_ATI,
|
||||
IQS62X_SYS_SETTINGS_ACK_RESET |
|
||||
IQS62X_SYS_SETTINGS_REDO_ATI);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & IQS62X_SYS_SETTINGS_CLK_DIV)
|
||||
clk_div = iqs62x->dev_desc->clk_div;
|
||||
|
||||
ret = regmap_write(iqs62x->regmap, IQS62X_SYS_SETTINGS, val |
|
||||
IQS62X_SYS_SETTINGS_ACK_RESET |
|
||||
IQS62X_SYS_SETTINGS_EVENT_MODE |
|
||||
IQS62X_SYS_SETTINGS_REDO_ATI);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(iqs62x->regmap, IQS62X_SYS_FLAGS, val,
|
||||
!(val & IQS62X_SYS_FLAGS_IN_ATI),
|
||||
IQS62X_ATI_POLL_SLEEP_US,
|
||||
IQS62X_ATI_POLL_TIMEOUT_US * clk_div);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msleep(IQS62X_ATI_STABLE_DELAY_MS * clk_div);
|
||||
/*
|
||||
* The following delay gives the device time to deassert its RDY output
|
||||
* in case a communication window was open while the REDO_ATI field was
|
||||
* written. This prevents an interrupt from being serviced prematurely.
|
||||
*/
|
||||
usleep_range(5000, 5100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -435,6 +443,11 @@ const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = {
|
|||
.mask = BIT(7),
|
||||
.val = BIT(7),
|
||||
},
|
||||
[IQS62X_EVENT_SYS_ATI] = {
|
||||
.reg = IQS62X_EVENT_SYS,
|
||||
.mask = BIT(2),
|
||||
.val = BIT(2),
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(iqs62x_events);
|
||||
|
||||
|
@ -469,7 +482,6 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
|
|||
switch (event_reg) {
|
||||
case IQS62X_EVENT_UI_LO:
|
||||
event_data.ui_data = get_unaligned_le16(&event_map[i]);
|
||||
|
||||
fallthrough;
|
||||
|
||||
case IQS62X_EVENT_UI_HI:
|
||||
|
@ -490,7 +502,6 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
|
|||
|
||||
case IQS62X_EVENT_HYST:
|
||||
event_map[i] <<= iqs62x->dev_desc->hyst_shift;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case IQS62X_EVENT_WHEEL:
|
||||
|
@ -525,19 +536,46 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
|
|||
"Failed to re-initialize device: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_RESET);
|
||||
reinit_completion(&iqs62x->ati_done);
|
||||
} else if (event_flags & BIT(IQS62X_EVENT_SYS_ATI)) {
|
||||
iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_ATI);
|
||||
reinit_completion(&iqs62x->ati_done);
|
||||
} else if (!completion_done(&iqs62x->ati_done)) {
|
||||
ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,
|
||||
IQS62X_SYS_SETTINGS_EVENT_MODE, 0xFF);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to enable event mode: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
msleep(IQS62X_FILT_SETTLE_MS);
|
||||
complete_all(&iqs62x->ati_done);
|
||||
}
|
||||
|
||||
ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
|
||||
&event_data);
|
||||
if (ret & NOTIFY_STOP_MASK)
|
||||
return IRQ_NONE;
|
||||
/*
|
||||
* Reset and ATI events are not broadcast to the sub-device drivers
|
||||
* until ATI has completed. Any other events that may have occurred
|
||||
* during ATI are ignored.
|
||||
*/
|
||||
if (completion_done(&iqs62x->ati_done)) {
|
||||
event_flags |= iqs62x->event_cache;
|
||||
ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
|
||||
&event_data);
|
||||
if (ret & NOTIFY_STOP_MASK)
|
||||
return IRQ_NONE;
|
||||
|
||||
iqs62x->event_cache = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Once the communication window is closed, a small delay is added to
|
||||
* ensure the device's RDY output has been deasserted by the time the
|
||||
* interrupt handler returns.
|
||||
*/
|
||||
usleep_range(50, 100);
|
||||
usleep_range(150, 200);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -571,6 +609,12 @@ static void iqs62x_firmware_load(const struct firmware *fw, void *context)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&iqs62x->ati_done,
|
||||
msecs_to_jiffies(2000))) {
|
||||
dev_err(&client->dev, "Failed to complete ATI\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
|
||||
iqs62x->dev_desc->sub_devs,
|
||||
iqs62x->dev_desc->num_sub_devs,
|
||||
|
@ -752,22 +796,17 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
|
|||
.dev_name = "iqs620at",
|
||||
.sub_devs = iqs620at_sub_devs,
|
||||
.num_sub_devs = ARRAY_SIZE(iqs620at_sub_devs),
|
||||
|
||||
.prod_num = IQS620_PROD_NUM,
|
||||
.sw_num = 0x08,
|
||||
.cal_regs = iqs620at_cal_regs,
|
||||
.num_cal_regs = ARRAY_SIZE(iqs620at_cal_regs),
|
||||
|
||||
.prox_mask = BIT(0),
|
||||
.sar_mask = BIT(1) | BIT(7),
|
||||
.hall_mask = BIT(2),
|
||||
.hyst_mask = BIT(3),
|
||||
.temp_mask = BIT(4),
|
||||
|
||||
.prox_settings = IQS620_PROX_SETTINGS_4,
|
||||
.hall_flags = IQS620_HALL_FLAGS,
|
||||
|
||||
.clk_div = 4,
|
||||
.fw_name = "iqs620a.bin",
|
||||
.event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
|
||||
},
|
||||
|
@ -775,20 +814,15 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
|
|||
.dev_name = "iqs620a",
|
||||
.sub_devs = iqs620a_sub_devs,
|
||||
.num_sub_devs = ARRAY_SIZE(iqs620a_sub_devs),
|
||||
|
||||
.prod_num = IQS620_PROD_NUM,
|
||||
.sw_num = 0x08,
|
||||
|
||||
.prox_mask = BIT(0),
|
||||
.sar_mask = BIT(1) | BIT(7),
|
||||
.hall_mask = BIT(2),
|
||||
.hyst_mask = BIT(3),
|
||||
.temp_mask = BIT(4),
|
||||
|
||||
.prox_settings = IQS620_PROX_SETTINGS_4,
|
||||
.hall_flags = IQS620_HALL_FLAGS,
|
||||
|
||||
.clk_div = 4,
|
||||
.fw_name = "iqs620a.bin",
|
||||
.event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
|
||||
},
|
||||
|
@ -796,23 +830,18 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
|
|||
.dev_name = "iqs621",
|
||||
.sub_devs = iqs621_sub_devs,
|
||||
.num_sub_devs = ARRAY_SIZE(iqs621_sub_devs),
|
||||
|
||||
.prod_num = IQS621_PROD_NUM,
|
||||
.sw_num = 0x09,
|
||||
.cal_regs = iqs621_cal_regs,
|
||||
.num_cal_regs = ARRAY_SIZE(iqs621_cal_regs),
|
||||
|
||||
.prox_mask = BIT(0),
|
||||
.hall_mask = BIT(1),
|
||||
.als_mask = BIT(2),
|
||||
.hyst_mask = BIT(3),
|
||||
.temp_mask = BIT(4),
|
||||
|
||||
.als_flags = IQS621_ALS_FLAGS,
|
||||
.hall_flags = IQS621_HALL_FLAGS,
|
||||
.hyst_shift = 5,
|
||||
|
||||
.clk_div = 2,
|
||||
.fw_name = "iqs621.bin",
|
||||
.event_regs = &iqs621_event_regs[IQS62X_UI_PROX],
|
||||
},
|
||||
|
@ -820,21 +849,16 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
|
|||
.dev_name = "iqs622",
|
||||
.sub_devs = iqs622_sub_devs,
|
||||
.num_sub_devs = ARRAY_SIZE(iqs622_sub_devs),
|
||||
|
||||
.prod_num = IQS622_PROD_NUM,
|
||||
.sw_num = 0x06,
|
||||
|
||||
.prox_mask = BIT(0),
|
||||
.sar_mask = BIT(1),
|
||||
.hall_mask = BIT(2),
|
||||
.als_mask = BIT(3),
|
||||
.ir_mask = BIT(4),
|
||||
|
||||
.prox_settings = IQS622_PROX_SETTINGS_4,
|
||||
.als_flags = IQS622_ALS_FLAGS,
|
||||
.hall_flags = IQS622_HALL_FLAGS,
|
||||
|
||||
.clk_div = 2,
|
||||
.fw_name = "iqs622.bin",
|
||||
.event_regs = &iqs622_event_regs[IQS62X_UI_PROX],
|
||||
},
|
||||
|
@ -842,14 +866,10 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
|
|||
.dev_name = "iqs624",
|
||||
.sub_devs = iqs624_sub_devs,
|
||||
.num_sub_devs = ARRAY_SIZE(iqs624_sub_devs),
|
||||
|
||||
.prod_num = IQS624_PROD_NUM,
|
||||
.sw_num = 0x0B,
|
||||
|
||||
.interval = IQS624_INTERVAL_NUM,
|
||||
.interval_div = 3,
|
||||
|
||||
.clk_div = 2,
|
||||
.fw_name = "iqs624.bin",
|
||||
.event_regs = &iqs624_event_regs[IQS62X_UI_PROX],
|
||||
},
|
||||
|
@ -857,20 +877,16 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
|
|||
.dev_name = "iqs625",
|
||||
.sub_devs = iqs625_sub_devs,
|
||||
.num_sub_devs = ARRAY_SIZE(iqs625_sub_devs),
|
||||
|
||||
.prod_num = IQS625_PROD_NUM,
|
||||
.sw_num = 0x0B,
|
||||
|
||||
.interval = IQS625_INTERVAL_NUM,
|
||||
.interval_div = 10,
|
||||
|
||||
.clk_div = 2,
|
||||
.fw_name = "iqs625.bin",
|
||||
.event_regs = &iqs625_event_regs[IQS62X_UI_PROX],
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config iqs62x_map_config = {
|
||||
static const struct regmap_config iqs62x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = IQS62X_MAX_REG,
|
||||
|
@ -894,9 +910,11 @@ static int iqs62x_probe(struct i2c_client *client)
|
|||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);
|
||||
INIT_LIST_HEAD(&iqs62x->fw_blk_head);
|
||||
|
||||
init_completion(&iqs62x->ati_done);
|
||||
init_completion(&iqs62x->fw_done);
|
||||
|
||||
iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_map_config);
|
||||
iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config);
|
||||
if (IS_ERR(iqs62x->regmap)) {
|
||||
ret = PTR_ERR(iqs62x->regmap);
|
||||
dev_err(&client->dev, "Failed to initialize register map: %d\n",
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
static const struct mfd_cell max8997_devs[] = {
|
||||
{ .name = "max8997-pmic", },
|
||||
{ .name = "max8997-rtc", },
|
||||
{ .name = "max8997-battery", },
|
||||
{ .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", },
|
||||
{ .name = "max8997-haptic", },
|
||||
{ .name = "max8997-muic", },
|
||||
{ .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", },
|
||||
{ .name = "max8997-led", .id = 1 },
|
||||
{ .name = "max8997-led", .id = 2 },
|
||||
};
|
||||
|
|
|
@ -214,8 +214,7 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
|
|||
* rate. This is the period for 3 64-bit frames. Always
|
||||
* round this time up.
|
||||
*/
|
||||
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
|
||||
mcp->sclk_rate;
|
||||
mcp->rw_timeout = DIV_ROUND_UP(64 * 3 * 1000000, mcp->sclk_rate);
|
||||
|
||||
ret = mcp_host_add(mcp, data->codec_pdata);
|
||||
if (ret == 0)
|
||||
|
|
|
@ -292,17 +292,17 @@ static const struct resource mt6360_ldo_resources[] = {
|
|||
};
|
||||
|
||||
static const struct mfd_cell mt6360_devs[] = {
|
||||
OF_MFD_CELL("mt6360_adc", mt6360_adc_resources,
|
||||
MFD_CELL_OF("mt6360_adc", mt6360_adc_resources,
|
||||
NULL, 0, 0, "mediatek,mt6360_adc"),
|
||||
OF_MFD_CELL("mt6360_chg", mt6360_chg_resources,
|
||||
MFD_CELL_OF("mt6360_chg", mt6360_chg_resources,
|
||||
NULL, 0, 0, "mediatek,mt6360_chg"),
|
||||
OF_MFD_CELL("mt6360_led", mt6360_led_resources,
|
||||
MFD_CELL_OF("mt6360_led", mt6360_led_resources,
|
||||
NULL, 0, 0, "mediatek,mt6360_led"),
|
||||
OF_MFD_CELL("mt6360_pmic", mt6360_pmic_resources,
|
||||
MFD_CELL_OF("mt6360_pmic", mt6360_pmic_resources,
|
||||
NULL, 0, 0, "mediatek,mt6360_pmic"),
|
||||
OF_MFD_CELL("mt6360_ldo", mt6360_ldo_resources,
|
||||
MFD_CELL_OF("mt6360_ldo", mt6360_ldo_resources,
|
||||
NULL, 0, 0, "mediatek,mt6360_ldo"),
|
||||
OF_MFD_CELL("mt6360_tcpc", NULL,
|
||||
MFD_CELL_OF("mt6360_tcpc", NULL,
|
||||
NULL, 0, 0, "mediatek,mt6360_tcpc"),
|
||||
};
|
||||
|
||||
|
|
|
@ -93,11 +93,10 @@ static int wm831x_auxadc_read_irq(struct wm831x *wm831x,
|
|||
wait_for_completion_timeout(&req->done, msecs_to_jiffies(500));
|
||||
|
||||
mutex_lock(&wm831x->auxadc_lock);
|
||||
|
||||
list_del(&req->list);
|
||||
ret = req->val;
|
||||
|
||||
out:
|
||||
list_del(&req->list);
|
||||
mutex_unlock(&wm831x->auxadc_lock);
|
||||
|
||||
kfree(req);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ROHM BD9571MWV-M regulator driver
|
||||
* ROHM BD9571MWV-M and BD9574MWF-M regulator driver
|
||||
*
|
||||
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
|
||||
*
|
||||
|
@ -9,6 +9,7 @@
|
|||
* NOTE: VD09 is missing
|
||||
*/
|
||||
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -17,7 +18,7 @@
|
|||
#include <linux/mfd/bd9571mwv.h>
|
||||
|
||||
struct bd9571mwv_reg {
|
||||
struct bd9571mwv *bd;
|
||||
struct regmap *regmap;
|
||||
|
||||
/* DDR Backup Power */
|
||||
u8 bkup_mode_cnt_keepon; /* from "rohm,ddr-backup-power" */
|
||||
|
@ -137,26 +138,30 @@ static const struct regulator_desc regulators[] = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int bd9571mwv_bkup_mode_read(struct bd9571mwv *bd, unsigned int *mode)
|
||||
static int bd9571mwv_bkup_mode_read(struct bd9571mwv_reg *bdreg,
|
||||
unsigned int *mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
|
||||
ret = regmap_read(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
|
||||
if (ret) {
|
||||
dev_err(bd->dev, "failed to read backup mode (%d)\n", ret);
|
||||
dev_err(regmap_get_device(bdreg->regmap),
|
||||
"failed to read backup mode (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode)
|
||||
static int bd9571mwv_bkup_mode_write(struct bd9571mwv_reg *bdreg,
|
||||
unsigned int mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
|
||||
ret = regmap_write(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
|
||||
if (ret) {
|
||||
dev_err(bd->dev, "failed to configure backup mode 0x%x (%d)\n",
|
||||
dev_err(regmap_get_device(bdreg->regmap),
|
||||
"failed to configure backup mode 0x%x (%d)\n",
|
||||
mode, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -194,7 +199,7 @@ static ssize_t backup_mode_store(struct device *dev,
|
|||
* Configure DDR Backup Mode, to change the role of the accessory power
|
||||
* switch from a power switch to a wake-up switch, or vice versa
|
||||
*/
|
||||
ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
|
||||
ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -202,7 +207,7 @@ static ssize_t backup_mode_store(struct device *dev,
|
|||
if (bdreg->bkup_mode_enabled)
|
||||
mode |= bdreg->bkup_mode_cnt_keepon;
|
||||
|
||||
ret = bd9571mwv_bkup_mode_write(bdreg->bd, mode);
|
||||
ret = bd9571mwv_bkup_mode_write(bdreg, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -221,7 +226,7 @@ static int bd9571mwv_suspend(struct device *dev)
|
|||
return 0;
|
||||
|
||||
/* Save DDR Backup Mode */
|
||||
ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
|
||||
ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -235,7 +240,7 @@ static int bd9571mwv_suspend(struct device *dev)
|
|||
mode |= bdreg->bkup_mode_cnt_keepon;
|
||||
|
||||
if (mode != bdreg->bkup_mode_cnt_saved)
|
||||
return bd9571mwv_bkup_mode_write(bdreg->bd, mode);
|
||||
return bd9571mwv_bkup_mode_write(bdreg, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -248,7 +253,7 @@ static int bd9571mwv_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
/* Restore DDR Backup Mode */
|
||||
return bd9571mwv_bkup_mode_write(bdreg->bd, bdreg->bkup_mode_cnt_saved);
|
||||
return bd9571mwv_bkup_mode_write(bdreg, bdreg->bkup_mode_cnt_saved);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops bd9571mwv_pm = {
|
||||
|
@ -268,51 +273,54 @@ static int bd9571mwv_regulator_remove(struct platform_device *pdev)
|
|||
|
||||
static int bd9571mwv_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent);
|
||||
struct regulator_config config = { };
|
||||
struct bd9571mwv_reg *bdreg;
|
||||
struct regulator_dev *rdev;
|
||||
unsigned int val;
|
||||
int i;
|
||||
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL);
|
||||
if (!bdreg)
|
||||
return -ENOMEM;
|
||||
|
||||
bdreg->bd = bd;
|
||||
bdreg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
|
||||
platform_set_drvdata(pdev, bdreg);
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.dev->of_node = bd->dev->of_node;
|
||||
config.driver_data = bd;
|
||||
config.regmap = bd->regmap;
|
||||
config.dev->of_node = pdev->dev.parent->of_node;
|
||||
config.driver_data = bdreg;
|
||||
config.regmap = bdreg->regmap;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
|
||||
/* BD9574MWF supports DVFS only */
|
||||
if (chip == ROHM_CHIP_TYPE_BD9574 && regulators[i].id != DVFS)
|
||||
continue;
|
||||
rdev = devm_regulator_register(&pdev->dev, ®ulators[i],
|
||||
&config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(bd->dev, "failed to register %s regulator\n",
|
||||
dev_err(&pdev->dev, "failed to register %s regulator\n",
|
||||
pdev->name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
}
|
||||
|
||||
val = 0;
|
||||
of_property_read_u32(bd->dev->of_node, "rohm,ddr-backup-power", &val);
|
||||
of_property_read_u32(config.dev->of_node, "rohm,ddr-backup-power", &val);
|
||||
if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) {
|
||||
dev_err(bd->dev, "invalid %s mode %u\n",
|
||||
dev_err(&pdev->dev, "invalid %s mode %u\n",
|
||||
"rohm,ddr-backup-power", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
bdreg->bkup_mode_cnt_keepon = val;
|
||||
|
||||
bdreg->rstbmode_level = of_property_read_bool(bd->dev->of_node,
|
||||
bdreg->rstbmode_level = of_property_read_bool(config.dev->of_node,
|
||||
"rohm,rstbmode-level");
|
||||
bdreg->rstbmode_pulse = of_property_read_bool(bd->dev->of_node,
|
||||
bdreg->rstbmode_pulse = of_property_read_bool(config.dev->of_node,
|
||||
"rohm,rstbmode-pulse");
|
||||
if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) {
|
||||
dev_err(bd->dev, "only one rohm,rstbmode-* may be specified");
|
||||
dev_err(&pdev->dev, "only one rohm,rstbmode-* may be specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -336,7 +344,8 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
|
||||
{ "bd9571mwv-regulator", },
|
||||
{ "bd9571mwv-regulator", ROHM_CHIP_TYPE_BD9571 },
|
||||
{ "bd9574mwf-regulator", ROHM_CHIP_TYPE_BD9574 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* ROHM BD9571MWV-M driver
|
||||
* ROHM BD9571MWV-M and BD9574MWF-M driver
|
||||
*
|
||||
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether expressed or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License version 2 for more details.
|
||||
* Copyright (C) 2020 Renesas Electronics Corporation
|
||||
*
|
||||
* Based on the TPS65086 driver
|
||||
*/
|
||||
|
@ -21,11 +14,12 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* List of registers for BD9571MWV */
|
||||
/* List of registers for BD9571MWV and BD9574MWF */
|
||||
#define BD9571MWV_VENDOR_CODE 0x00
|
||||
#define BD9571MWV_VENDOR_CODE_VAL 0xdb
|
||||
#define BD9571MWV_PRODUCT_CODE 0x01
|
||||
#define BD9571MWV_PRODUCT_CODE_VAL 0x60
|
||||
#define BD9571MWV_PRODUCT_CODE_BD9571MWV 0x60
|
||||
#define BD9571MWV_PRODUCT_CODE_BD9574MWF 0x74
|
||||
#define BD9571MWV_PRODUCT_REVISION 0x02
|
||||
|
||||
#define BD9571MWV_I2C_FUSA_MODE 0x10
|
||||
|
@ -55,6 +49,7 @@
|
|||
#define BD9571MWV_VD33_VID 0x44
|
||||
|
||||
#define BD9571MWV_DVFS_VINIT 0x50
|
||||
#define BD9574MWF_VD09_VINIT 0x51
|
||||
#define BD9571MWV_DVFS_SETVMAX 0x52
|
||||
#define BD9571MWV_DVFS_BOOSTVID 0x53
|
||||
#define BD9571MWV_DVFS_SETVID 0x54
|
||||
|
@ -68,6 +63,7 @@
|
|||
#define BD9571MWV_GPIO_INT_SET 0x64
|
||||
#define BD9571MWV_GPIO_INT 0x65
|
||||
#define BD9571MWV_GPIO_INTMASK 0x66
|
||||
#define BD9574MWF_GPIO_MUX 0x67
|
||||
|
||||
#define BD9571MWV_REG_KEEP(n) (0x70 + (n))
|
||||
|
||||
|
@ -77,6 +73,8 @@
|
|||
#define BD9571MWV_PROT_ERROR_STATUS2 0x83
|
||||
#define BD9571MWV_PROT_ERROR_STATUS3 0x84
|
||||
#define BD9571MWV_PROT_ERROR_STATUS4 0x85
|
||||
#define BD9574MWF_PROT_ERROR_STATUS5 0x86
|
||||
#define BD9574MWF_SYSTEM_ERROR_STATUS 0x87
|
||||
|
||||
#define BD9571MWV_INT_INTREQ 0x90
|
||||
#define BD9571MWV_INT_INTREQ_MD1_INT BIT(0)
|
||||
|
@ -89,6 +87,12 @@
|
|||
#define BD9571MWV_INT_INTREQ_BKUP_TRG_INT BIT(7)
|
||||
#define BD9571MWV_INT_INTMASK 0x91
|
||||
|
||||
#define BD9574MWF_SSCG_CNT 0xA0
|
||||
#define BD9574MWF_POFFB_MRB 0xA1
|
||||
#define BD9574MWF_SMRB_WR_PROT 0xA2
|
||||
#define BD9574MWF_SMRB_ASSERT 0xA3
|
||||
#define BD9574MWF_SMRB_STATUS 0xA4
|
||||
|
||||
#define BD9571MWV_ACCESS_KEY 0xff
|
||||
|
||||
/* Define the BD9571MWV IRQ numbers */
|
||||
|
@ -98,23 +102,8 @@ enum bd9571mwv_irqs {
|
|||
BD9571MWV_IRQ_MD2_E2,
|
||||
BD9571MWV_IRQ_PROT_ERR,
|
||||
BD9571MWV_IRQ_GP,
|
||||
BD9571MWV_IRQ_128H_OF,
|
||||
BD9571MWV_IRQ_128H_OF, /* BKUP_HOLD on BD9574MWF */
|
||||
BD9571MWV_IRQ_WDT_OF,
|
||||
BD9571MWV_IRQ_BKUP_TRG,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct bd9571mwv - state holder for the bd9571mwv driver
|
||||
*
|
||||
* Device data may be used to access the BD9571MWV chip
|
||||
*/
|
||||
struct bd9571mwv {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
|
||||
/* IRQ Data */
|
||||
int irq;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_BD9571MWV_H */
|
||||
|
|
|
@ -28,13 +28,13 @@
|
|||
.id = (_id), \
|
||||
}
|
||||
|
||||
#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg) \
|
||||
#define MFD_CELL_OF_REG(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg) \
|
||||
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, true, NULL)
|
||||
|
||||
#define OF_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _compat) \
|
||||
#define MFD_CELL_OF(_name, _res, _pdata, _pdsize, _id, _compat) \
|
||||
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, 0, false, NULL)
|
||||
|
||||
#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
|
||||
#define MFD_CELL_ACPI(_name, _res, _pdata, _pdsize, _id, _match) \
|
||||
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, _match)
|
||||
|
||||
#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
|
||||
|
|
|
@ -15,6 +15,15 @@
|
|||
|
||||
/* Register offset of system registers */
|
||||
#define NIOS2_FW_VERSION 0x0
|
||||
#define M10BMC_MAC_LOW 0x10
|
||||
#define M10BMC_MAC_BYTE4 GENMASK(7, 0)
|
||||
#define M10BMC_MAC_BYTE3 GENMASK(15, 8)
|
||||
#define M10BMC_MAC_BYTE2 GENMASK(23, 16)
|
||||
#define M10BMC_MAC_BYTE1 GENMASK(31, 24)
|
||||
#define M10BMC_MAC_HIGH 0x14
|
||||
#define M10BMC_MAC_BYTE6 GENMASK(7, 0)
|
||||
#define M10BMC_MAC_BYTE5 GENMASK(15, 8)
|
||||
#define M10BMC_MAC_COUNT GENMASK(23, 16)
|
||||
#define M10BMC_TEST_REG 0x3c
|
||||
#define M10BMC_BUILD_VER 0x68
|
||||
#define M10BMC_VER_MAJOR_MSK GENMASK(23, 16)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#define IQS620_GLBL_EVENT_MASK_PMU BIT(6)
|
||||
|
||||
#define IQS62X_NUM_KEYS 16
|
||||
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 5)
|
||||
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 6)
|
||||
|
||||
#define IQS62X_EVENT_SIZE 10
|
||||
|
||||
|
@ -78,6 +78,7 @@ enum iqs62x_event_flag {
|
|||
|
||||
/* everything else */
|
||||
IQS62X_EVENT_SYS_RESET,
|
||||
IQS62X_EVENT_SYS_ATI,
|
||||
};
|
||||
|
||||
struct iqs62x_event_data {
|
||||
|
@ -97,12 +98,10 @@ struct iqs62x_dev_desc {
|
|||
const char *dev_name;
|
||||
const struct mfd_cell *sub_devs;
|
||||
int num_sub_devs;
|
||||
|
||||
u8 prod_num;
|
||||
u8 sw_num;
|
||||
const u8 *cal_regs;
|
||||
int num_cal_regs;
|
||||
|
||||
u8 prox_mask;
|
||||
u8 sar_mask;
|
||||
u8 hall_mask;
|
||||
|
@ -110,16 +109,12 @@ struct iqs62x_dev_desc {
|
|||
u8 temp_mask;
|
||||
u8 als_mask;
|
||||
u8 ir_mask;
|
||||
|
||||
u8 prox_settings;
|
||||
u8 als_flags;
|
||||
u8 hall_flags;
|
||||
u8 hyst_shift;
|
||||
|
||||
u8 interval;
|
||||
u8 interval_div;
|
||||
|
||||
u8 clk_div;
|
||||
const char *fw_name;
|
||||
const enum iqs62x_event_reg (*event_regs)[IQS62X_EVENT_SIZE];
|
||||
};
|
||||
|
@ -130,8 +125,10 @@ struct iqs62x_core {
|
|||
struct regmap *regmap;
|
||||
struct blocking_notifier_head nh;
|
||||
struct list_head fw_blk_head;
|
||||
struct completion ati_done;
|
||||
struct completion fw_done;
|
||||
enum iqs62x_ui_sel ui_sel;
|
||||
unsigned long event_cache;
|
||||
};
|
||||
|
||||
extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];
|
||||
|
|
|
@ -12,6 +12,8 @@ enum rohm_chip_type {
|
|||
ROHM_CHIP_TYPE_BD71847,
|
||||
ROHM_CHIP_TYPE_BD70528,
|
||||
ROHM_CHIP_TYPE_BD71828,
|
||||
ROHM_CHIP_TYPE_BD9571,
|
||||
ROHM_CHIP_TYPE_BD9574,
|
||||
ROHM_CHIP_TYPE_AMOUNT
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue