提交 6eb59af5 编写于 作者: L Linus Torvalds

Merge tag 'mfd-for-linus-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd

Pull MFD updates from Lee Jones:
 "New Drivers:
   - Add new driver for MAXIM MAX77620/MAX20024 PMIC
   - Add new driver for Hisilicon HI665X PMIC

  New Device Support:
   - Add support for AXP809 in axp20x-rsb
   - Add support for Power Supply in axp20x

  New core features:
   - devm_mfd_* managed resources

  Fix-ups:
   - Remove unused code (da9063-irq, wm8400-core, tps6105x,
     smsc-ece1099, twl4030-power)
   - Improve clean-up in error path (intel_quark_i2c_gpio)
   - Explicitly include headers (syscon.h)
   - Allow building as modules (max77693)
   - Use IS_ENABLED() instead of rolling your own (dm355evm_msp,
     wm8400-core)
   - DT adaptions (axp20x, hi655x, arizona, max77620)
   - Remove CLK_IS_ROOT flag (intel-lpss, intel_quark)
   - Move to gpiochip API (asic3, dm355evm_msp, htc-egpio, htc-i2cpld,
     sm501, tc6393xb, tps65010, ucb1x00, vexpress)
   - Make use of devm_mfd_* calls (act8945a, as3711, atmel-hlcdc,
     bcm590xx, hi6421-pmic-core, lp3943, menf21bmc, mt6397, rdc321x,
     rk808, rn5t618, rt5033, sky81452, stw481x, tps6507x, tps65217,
     wm8400)

  Bug Fixes"
   - Fix ACPI child matching (mfd-core)
   - Fix start-up ordering issues (mt6397-core, arizona-core)
   - Fix forgotten register state on resume (intel-lpss)
   - Fix Clock related issues (twl6040)
   - Fix scheduling whilst atomic (omap-usb-tll)
   - Kconfig changes (vexpress)"

* tag 'mfd-for-linus-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (73 commits)
  mfd: hi655x: Add MFD driver for hi655x
  mfd: ab8500-debugfs: Trivial fix of spelling mistake on "between"
  mfd: vexpress: Add !ARCH_USES_GETTIMEOFFSET dependency
  mfd: Add device-tree binding doc for PMIC MAX77620/MAX20024
  mfd: max77620: Add core driver for MAX77620/MAX20024
  mfd: arizona: Add defines for GPSW values that can be used from DT
  mfd: omap-usb-tll: Fix scheduling while atomic BUG
  mfd: wm5110: ARIZONA_CLOCK_CONTROL should be volatile
  mfd: axp20x: Add a cell for the ac power_supply part of the axp20x PMICs
  mfd: intel_soc_pmic_core: Terminate panel control GPIO lookup table correctly
  mfd: wl1273-core: Use devm_mfd_add_devices() for mfd_device registration
  mfd: tps65910: Use devm_mfd_add_devices and devm_regmap_add_irq_chip
  mfd: sec: Use devm_mfd_add_devices and devm_regmap_add_irq_chip
  mfd: rc5t583: Use devm_mfd_add_devices and devm_request_threaded_irq
  mfd: max77686: Use devm_mfd_add_devices and devm_regmap_add_irq_chip
  mfd: as3722: Use devm_mfd_add_devices and devm_regmap_add_irq_chip
  mfd: twl4030-power: Remove driver path in file comment
  MAINTAINERS: Add entry for X-Powers AXP family PMIC drivers
  mfd: smsc-ece1099: Remove unnecessarily remove callback
  mfd: Use IS_ENABLED(CONFIG_FOO) instead of checking FOO || FOO_MODULE
  ...
......@@ -6,10 +6,11 @@ axp202 (X-Powers)
axp209 (X-Powers)
axp221 (X-Powers)
axp223 (X-Powers)
axp809 (X-Powers)
Required properties:
- compatible: "x-powers,axp152", "x-powers,axp202", "x-powers,axp209",
"x-powers,axp221", "x-powers,axp223"
"x-powers,axp221", "x-powers,axp223", "x-powers,axp809"
- reg: The I2C slave address or RSB hardware address for the AXP chip
- interrupt-parent: The parent interrupt controller
- interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin
......@@ -18,7 +19,9 @@ Required properties:
Optional properties:
- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz
(range: 750-1875). Default: 1.5MHz
AXP152/20X: range: 750-1875, Default: 1.5 MHz
AXP22X/80X: range: 1800-4050, Default: 3 MHz
- <input>-supply: a phandle to the regulator supply node. May be omitted if
inputs are unregulated, such as using the IPSOUT output
from the PMIC.
......@@ -77,6 +80,30 @@ LDO_IO0 : LDO : ips-supply : GPIO 0
LDO_IO1 : LDO : ips-supply : GPIO 1
RTC_LDO : LDO : ips-supply : always on
AXP809 regulators, type, and corresponding input supply names:
Regulator Type Supply Name Notes
--------- ---- ----------- -----
DCDC1 : DC-DC buck : vin1-supply
DCDC2 : DC-DC buck : vin2-supply
DCDC3 : DC-DC buck : vin3-supply
DCDC4 : DC-DC buck : vin4-supply
DCDC5 : DC-DC buck : vin5-supply
DC1SW : On/Off Switch : : DCDC1 secondary output
DC5LDO : LDO : : input from DCDC5
ALDO1 : LDO : aldoin-supply : shared supply
ALDO2 : LDO : aldoin-supply : shared supply
ALDO3 : LDO : aldoin-supply : shared supply
DLDO1 : LDO : dldoin-supply : shared supply
DLDO2 : LDO : dldoin-supply : shared supply
ELDO1 : LDO : eldoin-supply : shared supply
ELDO2 : LDO : eldoin-supply : shared supply
ELDO3 : LDO : eldoin-supply : shared supply
LDO_IO0 : LDO : ips-supply : GPIO 0
LDO_IO1 : LDO : ips-supply : GPIO 1
RTC_LDO : LDO : ips-supply : always on
SW : On/Off Switch : swin-supply
Example:
axp209: pmic@34 {
......
Hisilicon Hi655x Power Management Integrated Circuit (PMIC)
The hardware layout for access PMIC Hi655x from AP SoC Hi6220.
Between PMIC Hi655x and Hi6220, the physical signal channel is SSI.
We can use memory-mapped I/O to communicate.
+----------------+ +-------------+
| | | |
| Hi6220 | SSI bus | Hi655x |
| |-------------| |
| |(REGMAP_MMIO)| |
+----------------+ +-------------+
Required properties:
- compatible: Should be "hisilicon,hi655x-pmic".
- reg: Base address of PMIC on Hi6220 SoC.
- interrupt-controller: Hi655x has internal IRQs (has own IRQ domain).
- pmic-gpios: The GPIO used by PMIC IRQ.
Example:
pmic: pmic@f8000000 {
compatible = "hisilicon,hi655x-pmic";
reg = <0x0 0xf8000000 0x0 0x1000>;
interrupt-controller;
#interrupt-cells = <2>;
pmic-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
}
MAX77620 Power management IC from Maxim Semiconductor.
Required properties:
-------------------
- compatible: Must be one of
"maxim,max77620"
"maxim,max20024".
- reg: I2C device address.
Optional properties:
-------------------
- interrupts: The interrupt on the parent the controller is
connected to.
- interrupt-controller: Marks the device node as an interrupt controller.
- #interrupt-cells: is <2> and their usage is compliant to the 2 cells
variant of <../interrupt-controller/interrupts.txt>
IRQ numbers for different interrupt source of MAX77620
are defined at dt-bindings/mfd/max77620.h.
Optional subnodes and their properties:
=======================================
Flexible power sequence configurations:
--------------------------------------
The Flexible Power Sequencer (FPS) allows each regulator to power up under
hardware or software control. Additionally, each regulator can power on
independently or among a group of other regulators with an adjustable power-up
and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can be programmed
to be part of a sequence allowing external regulators to be sequenced along
with internal regulators. 32KHz clock can be programmed to be part of a
sequence.
The flexible sequencing structure consists of two hardware enable inputs
(EN0, EN1), and 3 master sequencing timers called FPS0, FPS1 and FPS2.
Each master sequencing timer is programmable through its configuration
register to have a hardware enable source (EN1 or EN2) or a software enable
source (SW). When enabled/disabled, the master sequencing timer generates
eight sequencing events on different time periods called slots. The time
period between each event is programmable within the configuration register.
Each regulator, GPIO1, GPIO2, GPIO3, and 32KHz clock has a flexible power
sequence slave register which allows its enable source to be specified as
a flexible power sequencer timer or a software bit. When a FPS source of
regulators, GPIOs and clocks specifies the enable source to be a flexible
power sequencer, the power up and power down delays can be specified in
the regulators, GPIOs and clocks flexible power sequencer configuration
registers.
When FPS event cleared (set to LOW), regulators, GPIOs and 32KHz
clock are set into following state at the sequencing event that
corresponds to its flexible sequencer configuration register.
Sleep state: In this state, regulators, GPIOs
and 32KHz clock get disabled at
the sequencing event.
Global Low Power Mode (GLPM): In this state, regulators are set in
low power mode at the sequencing event.
The configuration parameters of FPS is provided through sub-node "fps"
and their child for FPS specific. The child node name for FPS are "fps0",
"fps1", and "fps2" for FPS0, FPS1 and FPS2 respectively.
The FPS configurations like FPS source, power up and power down slots for
regulators, GPIOs and 32kHz clocks are provided in their respective
configuration nodes which is explained in respective sub-system DT
binding document.
There is need for different FPS configuration parameters based on system
state like when system state changed from active to suspend or active to
power off (shutdown).
Optional properties:
-------------------
-maxim,fps-event-source: u32, FPS event source like external
hardware input to PMIC i.e. EN0, EN1 or
software (SW).
The macros are defined on
dt-bindings/mfd/max77620.h
for different control source.
- MAX77620_FPS_EVENT_SRC_EN0
for hardware input pin EN0.
- MAX77620_FPS_EVENT_SRC_EN1
for hardware input pin EN1.
- MAX77620_FPS_EVENT_SRC_SW
for software control.
-maxim,shutdown-fps-time-period-us: u32, FPS time period in microseconds
when system enters in to shutdown
state.
-maxim,suspend-fps-time-period-us: u32, FPS time period in microseconds
when system enters in to suspend state.
-maxim,device-state-on-disabled-event: u32, describe the PMIC state when FPS
event cleared (set to LOW) whether it
should go to sleep state or low-power
state. Following are valid values:
- MAX77620_FPS_INACTIVE_STATE_SLEEP
to set the PMIC state to sleep.
- MAX77620_FPS_INACTIVE_STATE_LOW_POWER
to set the PMIC state to low
power.
Absence of this property or other value
will not change device state when FPS
event get cleared.
Here supported time periods by device in microseconds are as follows:
MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds.
MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds.
For DT binding details of different sub modules like GPIO, pincontrol,
regulator, power, please refer respective device-tree binding document
under their respective sub-system directories.
Example:
--------
#include <dt-bindings/mfd/max77620.h>
max77620@3c {
compatible = "maxim,max77620";
reg = <0x3c>;
interrupt-parent = <&intc>;
interrupts = <0 86 IRQ_TYPE_NONE>;
interrupt-controller;
#interrupt-cells = <2>;
fps {
fps0 {
maxim,shutdown-fps-time-period-us = <1280>;
maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN1>;
};
fps1 {
maxim,shutdown-fps-time-period-us = <1280>;
maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
};
fps2 {
maxim,shutdown-fps-time-period-us = <1280>;
maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_SW>;
};
};
};
......@@ -320,6 +320,9 @@ MEM
devm_kvasprintf()
devm_kzalloc()
MFD
devm_mfd_add_devices()
PCI
pcim_enable_device() : after success, all PCI ops become managed
pcim_pin_device() : keep PCI device enabled after release
......
......@@ -12291,6 +12291,12 @@ F: include/linux/workqueue.h
F: kernel/workqueue.c
F: Documentation/workqueue.txt
X-POWERS MULTIFUNCTION PMIC DEVICE DRIVERS
M: Chen-Yu Tsai <wens@csie.org>
L: linux-kernel@vger.kernel.org
S: Maintained
N: axp[128]
X.25 NETWORK LAYER
M: Andrew Hendry <andrew.hendry@gmail.com>
L: linux-x25@vger.kernel.org
......
......@@ -134,7 +134,7 @@ config MFD_CROS_EC
select MFD_CORE
select CHROME_PLATFORMS
select CROS_EC_PROTO
depends on X86 || ARM || COMPILE_TEST
depends on X86 || ARM || ARM64 || COMPILE_TEST
help
If you say Y here you get support for the ChromeOS Embedded
Controller (EC) providing keyboard, battery and power services.
......@@ -319,6 +319,16 @@ config MFD_HI6421_PMIC
menus in order to enable them.
We communicate with the Hi6421 via memory-mapped I/O.
config MFD_HI655X_PMIC
tristate "HiSilicon Hi655X series PMU/Codec IC"
depends on ARCH_HISI || COMPILE_TEST
depends on OF
select MFD_CORE
select REGMAP_MMIO
select REGMAP_IRQ
help
Select this option to enable Hisilicon hi655x series pmic driver.
config HTC_EGPIO
bool "HTC EGPIO support"
depends on GPIOLIB && ARM
......@@ -527,6 +537,21 @@ config MFD_MAX14577
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_MAX77620
bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
depends on I2C=y
depends on OF
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
select IRQ_DOMAIN
help
Say yes here to add support for Maxim Semiconductor MAX77620 and
MAX20024 which are Power Management IC with General purpose pins,
RTC, regulators, clock generator, watchdog etc. This driver
provides common support for accessing the device; additional drivers
must be enabled in order to use the functionality of the device.
config MFD_MAX77686
tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
depends on I2C
......@@ -543,8 +568,8 @@ config MFD_MAX77686
of the device.
config MFD_MAX77693
bool "Maxim Semiconductor MAX77693 PMIC Support"
depends on I2C=y
tristate "Maxim Semiconductor MAX77693 PMIC Support"
depends on I2C
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
......@@ -1568,7 +1593,7 @@ endmenu
config MFD_VEXPRESS_SYSREG
bool "Versatile Express System Registers"
depends on VEXPRESS_CONFIG && GPIOLIB
depends on VEXPRESS_CONFIG && GPIOLIB && !ARCH_USES_GETTIMEOFFSET
default y
select CLKSRC_MMIO
select GPIO_GENERIC_PLATFORM
......
......@@ -128,6 +128,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o
obj-$(CONFIG_MFD_DA9150) += da9150-core.o
obj-$(CONFIG_MFD_MAX14577) += max14577.o
obj-$(CONFIG_MFD_MAX77620) += max77620.o
obj-$(CONFIG_MFD_MAX77686) += max77686.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o
obj-$(CONFIG_MFD_MAX77843) += max77843.o
......@@ -195,6 +196,7 @@ obj-$(CONFIG_MFD_STW481X) += stw481x.o
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
......
......@@ -46,8 +46,9 @@ static int act8945a_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, regmap);
ret = mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE, act8945a_devs,
ARRAY_SIZE(act8945a_devs), NULL, 0, NULL);
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE,
act8945a_devs, ARRAY_SIZE(act8945a_devs),
NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "Failed to add sub devices\n");
return ret;
......@@ -56,13 +57,6 @@ static int act8945a_i2c_probe(struct i2c_client *i2c,
return 0;
}
static int act8945a_i2c_remove(struct i2c_client *i2c)
{
mfd_remove_devices(&i2c->dev);
return 0;
}
static const struct i2c_device_id act8945a_i2c_id[] = {
{ "act8945a", 0 },
{}
......@@ -81,7 +75,6 @@ static struct i2c_driver act8945a_i2c_driver = {
.of_match_table = of_match_ptr(act8945a_of_match),
},
.probe = act8945a_i2c_probe,
.remove = act8945a_i2c_remove,
.id_table = act8945a_i2c_id,
};
......
......@@ -908,12 +908,12 @@ static const char * const wm5102_supplies[] = {
static const struct mfd_cell wm5102_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm5102_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -925,12 +925,12 @@ static const struct mfd_cell wm5102_devs[] = {
static const struct mfd_cell wm5110_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm5102_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -966,12 +966,12 @@ static const char * const wm8997_supplies[] = {
static const struct mfd_cell wm8997_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm8997_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -982,12 +982,13 @@ static const struct mfd_cell wm8997_devs[] = {
};
static const struct mfd_cell wm8998_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm5102_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -995,7 +996,6 @@ static const struct mfd_cell wm8998_devs[] = {
.parent_supplies = wm5102_supplies,
.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
},
{ .name = "arizona-micsupp" },
};
int arizona_dev_init(struct arizona *arizona)
......
......@@ -168,12 +168,15 @@ static struct irq_chip arizona_irq_chip = {
.irq_set_wake = arizona_irq_set_wake,
};
static struct lock_class_key arizona_irq_lock_class;
static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct arizona *data = h->host_data;
irq_set_chip_data(virq, data);
irq_set_lockdep_class(virq, &arizona_irq_lock_class);
irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq);
irq_set_nested_thread(virq, 1);
irq_set_noprobe(virq);
......
......@@ -189,7 +189,7 @@ static int as3711_i2c_probe(struct i2c_client *client,
as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 0;
}
ret = mfd_add_devices(as3711->dev, -1, as3711_subdevs,
ret = devm_mfd_add_devices(as3711->dev, -1, as3711_subdevs,
ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL);
if (ret < 0)
dev_err(&client->dev, "add mfd devices failed: %d\n", ret);
......@@ -197,14 +197,6 @@ static int as3711_i2c_probe(struct i2c_client *client,
return ret;
}
static int as3711_i2c_remove(struct i2c_client *client)
{
struct as3711 *as3711 = i2c_get_clientdata(client);
mfd_remove_devices(as3711->dev);
return 0;
}
static const struct i2c_device_id as3711_i2c_id[] = {
{.name = "as3711", .driver_data = 0},
{}
......@@ -218,7 +210,6 @@ static struct i2c_driver as3711_i2c_driver = {
.of_match_table = of_match_ptr(as3711_of_match),
},
.probe = as3711_i2c_probe,
.remove = as3711_i2c_remove,
.id_table = as3711_i2c_id,
};
......
......@@ -385,7 +385,8 @@ static int as3722_i2c_probe(struct i2c_client *i2c,
return ret;
irq_flags = as3722->irq_flags | IRQF_ONESHOT;
ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq,
ret = devm_regmap_add_irq_chip(as3722->dev, as3722->regmap,
as3722->chip_irq,
irq_flags, -1, &as3722_irq_chip,
&as3722->irq_data);
if (ret < 0) {
......@@ -395,33 +396,20 @@ static int as3722_i2c_probe(struct i2c_client *i2c,
ret = as3722_configure_pullups(as3722);
if (ret < 0)
goto scrub;
return ret;
ret = mfd_add_devices(&i2c->dev, -1, as3722_devs,
ret = devm_mfd_add_devices(&i2c->dev, -1, as3722_devs,
ARRAY_SIZE(as3722_devs), NULL, 0,
regmap_irq_get_domain(as3722->irq_data));
if (ret) {
dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret);
goto scrub;
return ret;
}
device_init_wakeup(as3722->dev, true);
dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
return 0;
scrub:
regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
return ret;
}
static int as3722_i2c_remove(struct i2c_client *i2c)
{
struct as3722 *as3722 = i2c_get_clientdata(i2c);
mfd_remove_devices(as3722->dev);
regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
return 0;
}
static int __maybe_unused as3722_i2c_suspend(struct device *dev)
......@@ -470,7 +458,6 @@ static struct i2c_driver as3722_i2c_driver = {
.pm = &as3722_pm_ops,
},
.probe = as3722_i2c_probe,
.remove = as3722_i2c_remove,
.id_table = as3722_i2c_id,
};
......
......@@ -446,7 +446,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip,
unsigned long flags;
struct asic3 *asic;
asic = container_of(chip, struct asic3, gpio);
asic = gpiochip_get_data(chip);
gpio_base = ASIC3_GPIO_TO_BASE(offset);
if (gpio_base > ASIC3_GPIO_D_BASE) {
......@@ -492,7 +492,7 @@ static int asic3_gpio_get(struct gpio_chip *chip,
u32 mask = ASIC3_GPIO_TO_MASK(offset);
struct asic3 *asic;
asic = container_of(chip, struct asic3, gpio);
asic = gpiochip_get_data(chip);
gpio_base = ASIC3_GPIO_TO_BASE(offset);
if (gpio_base > ASIC3_GPIO_D_BASE) {
......@@ -513,7 +513,7 @@ static void asic3_gpio_set(struct gpio_chip *chip,
unsigned long flags;
struct asic3 *asic;
asic = container_of(chip, struct asic3, gpio);
asic = gpiochip_get_data(chip);
gpio_base = ASIC3_GPIO_TO_BASE(offset);
if (gpio_base > ASIC3_GPIO_D_BASE) {
......@@ -540,7 +540,7 @@ static void asic3_gpio_set(struct gpio_chip *chip,
static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct asic3 *asic = container_of(chip, struct asic3, gpio);
struct asic3 *asic = gpiochip_get_data(chip);
return asic->irq_base + offset;
}
......@@ -595,7 +595,7 @@ static __init int asic3_gpio_probe(struct platform_device *pdev,
alt_reg[i]);
}
return gpiochip_add(&asic->gpio);
return gpiochip_add_data(&asic->gpio, asic);
}
static int asic3_gpio_remove(struct platform_device *pdev)
......
......@@ -128,18 +128,11 @@ static int atmel_hlcdc_probe(struct platform_device *pdev)
dev_set_drvdata(dev, hlcdc);
return mfd_add_devices(dev, -1, atmel_hlcdc_cells,
return devm_mfd_add_devices(dev, -1, atmel_hlcdc_cells,
ARRAY_SIZE(atmel_hlcdc_cells),
NULL, 0, NULL);
}
static int atmel_hlcdc_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
return 0;
}
static const struct of_device_id atmel_hlcdc_match[] = {
{ .compatible = "atmel,at91sam9n12-hlcdc" },
{ .compatible = "atmel,at91sam9x5-hlcdc" },
......@@ -152,7 +145,6 @@ MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
static struct platform_driver atmel_hlcdc_driver = {
.probe = atmel_hlcdc_probe,
.remove = atmel_hlcdc_remove,
.driver = {
.name = "atmel-hlcdc",
.of_match_table = atmel_hlcdc_match,
......
......@@ -61,6 +61,7 @@ static int axp20x_rsb_remove(struct sunxi_rsb_device *rdev)
static const struct of_device_id axp20x_rsb_of_match[] = {
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
{ .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
{ },
};
MODULE_DEVICE_TABLE(of, axp20x_rsb_of_match);
......
......@@ -37,6 +37,7 @@ static const char * const axp20x_model_names[] = {
"AXP221",
"AXP223",
"AXP288",
"AXP809",
};
static const struct regmap_range axp152_writeable_ranges[] = {
......@@ -85,6 +86,7 @@ static const struct regmap_access_table axp20x_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
};
/* AXP22x ranges are shared with the AXP809, as they cover the same range */
static const struct regmap_range axp22x_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1),
......@@ -128,6 +130,12 @@ static struct resource axp152_pek_resources[] = {
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
};
static struct resource axp20x_ac_power_supply_resources[] = {
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"),
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"),
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_OVER_V, "ACIN_OVER_V"),
};
static struct resource axp20x_pek_resources[] = {
{
.name = "PEK_DBR",
......@@ -211,6 +219,20 @@ static struct resource axp288_fuel_gauge_resources[] = {
},
};
static struct resource axp809_pek_resources[] = {
{
.name = "PEK_DBR",
.start = AXP809_IRQ_PEK_RIS_EDGE,
.end = AXP809_IRQ_PEK_RIS_EDGE,
.flags = IORESOURCE_IRQ,
}, {
.name = "PEK_DBF",
.start = AXP809_IRQ_PEK_FAL_EDGE,
.end = AXP809_IRQ_PEK_FAL_EDGE,
.flags = IORESOURCE_IRQ,
},
};
static const struct regmap_config axp152_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
......@@ -378,6 +400,41 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
};
static const struct regmap_irq axp809_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP809, ACIN_OVER_V, 0, 7),
INIT_REGMAP_IRQ(AXP809, ACIN_PLUGIN, 0, 6),
INIT_REGMAP_IRQ(AXP809, ACIN_REMOVAL, 0, 5),
INIT_REGMAP_IRQ(AXP809, VBUS_OVER_V, 0, 4),
INIT_REGMAP_IRQ(AXP809, VBUS_PLUGIN, 0, 3),
INIT_REGMAP_IRQ(AXP809, VBUS_REMOVAL, 0, 2),
INIT_REGMAP_IRQ(AXP809, VBUS_V_LOW, 0, 1),
INIT_REGMAP_IRQ(AXP809, BATT_PLUGIN, 1, 7),
INIT_REGMAP_IRQ(AXP809, BATT_REMOVAL, 1, 6),
INIT_REGMAP_IRQ(AXP809, BATT_ENT_ACT_MODE, 1, 5),
INIT_REGMAP_IRQ(AXP809, BATT_EXIT_ACT_MODE, 1, 4),
INIT_REGMAP_IRQ(AXP809, CHARG, 1, 3),
INIT_REGMAP_IRQ(AXP809, CHARG_DONE, 1, 2),
INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_HIGH, 2, 7),
INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_HIGH_END, 2, 6),
INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_LOW, 2, 5),
INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_LOW_END, 2, 4),
INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_HIGH, 2, 3),
INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_HIGH_END, 2, 2),
INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_LOW, 2, 1),
INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_LOW_END, 2, 0),
INIT_REGMAP_IRQ(AXP809, DIE_TEMP_HIGH, 3, 7),
INIT_REGMAP_IRQ(AXP809, LOW_PWR_LVL1, 3, 1),
INIT_REGMAP_IRQ(AXP809, LOW_PWR_LVL2, 3, 0),
INIT_REGMAP_IRQ(AXP809, TIMER, 4, 7),
INIT_REGMAP_IRQ(AXP809, PEK_RIS_EDGE, 4, 6),
INIT_REGMAP_IRQ(AXP809, PEK_FAL_EDGE, 4, 5),
INIT_REGMAP_IRQ(AXP809, PEK_SHORT, 4, 4),
INIT_REGMAP_IRQ(AXP809, PEK_LONG, 4, 3),
INIT_REGMAP_IRQ(AXP809, PEK_OVER_OFF, 4, 2),
INIT_REGMAP_IRQ(AXP809, GPIO1_INPUT, 4, 1),
INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0),
};
static const struct regmap_irq_chip axp152_regmap_irq_chip = {
.name = "axp152_irq_chip",
.status_base = AXP152_IRQ1_STATE,
......@@ -428,6 +485,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = {
};
static const struct regmap_irq_chip axp809_regmap_irq_chip = {
.name = "axp809",
.status_base = AXP20X_IRQ1_STATE,
.ack_base = AXP20X_IRQ1_STATE,
.mask_base = AXP20X_IRQ1_EN,
.mask_invert = true,
.init_ack_masked = true,
.irqs = axp809_regmap_irqs,
.num_irqs = ARRAY_SIZE(axp809_regmap_irqs),
.num_regs = 5,
};
static struct mfd_cell axp20x_cells[] = {
{
.name = "axp20x-pek",
......@@ -435,6 +504,11 @@ static struct mfd_cell axp20x_cells[] = {
.resources = axp20x_pek_resources,
}, {
.name = "axp20x-regulator",
}, {
.name = "axp20x-ac-power-supply",
.of_compatible = "x-powers,axp202-ac-power-supply",
.num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources),
.resources = axp20x_ac_power_supply_resources,
}, {
.name = "axp20x-usb-power-supply",
.of_compatible = "x-powers,axp202-usb-power-supply",
......@@ -572,6 +646,16 @@ static struct mfd_cell axp288_cells[] = {
},
};
static struct mfd_cell axp809_cells[] = {
{
.name = "axp20x-pek",
.num_resources = ARRAY_SIZE(axp809_pek_resources),
.resources = axp809_pek_resources,
}, {
.name = "axp20x-regulator",
},
};
static struct axp20x_dev *axp20x_pm_power_off;
static void axp20x_power_off(void)
{
......@@ -631,6 +715,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_cfg = &axp288_regmap_config;
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
break;
case AXP809_ID:
axp20x->nr_cells = ARRAY_SIZE(axp809_cells);
axp20x->cells = axp809_cells;
axp20x->regmap_cfg = &axp22x_regmap_config;
axp20x->regmap_irq_chip = &axp809_regmap_irq_chip;
break;
default:
dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
return -EINVAL;
......
......@@ -82,7 +82,7 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri,
goto err;
}
ret = mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs,
ret = devm_mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs,
ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL);
if (ret < 0) {
dev_err(&i2c_pri->dev, "failed to add sub-devices: %d\n", ret);
......@@ -96,12 +96,6 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri,
return ret;
}
static int bcm590xx_i2c_remove(struct i2c_client *i2c)
{
mfd_remove_devices(&i2c->dev);
return 0;
}
static const struct of_device_id bcm590xx_of_match[] = {
{ .compatible = "brcm,bcm59056" },
{ }
......@@ -120,7 +114,6 @@ static struct i2c_driver bcm590xx_i2c_driver = {
.of_match_table = of_match_ptr(bcm590xx_of_match),
},
.probe = bcm590xx_i2c_probe,
.remove = bcm590xx_i2c_remove,
.id_table = bcm590xx_i2c_id,
};
module_i2c_driver(bcm590xx_i2c_driver);
......
......@@ -25,14 +25,6 @@
#define DA9063_REG_EVENT_B_OFFSET 1
#define DA9063_REG_EVENT_C_OFFSET 2
#define DA9063_REG_EVENT_D_OFFSET 3
#define EVENTS_BUF_LEN 4
static const u8 mask_events_buf[] = { [0 ... (EVENTS_BUF_LEN - 1)] = ~0 };
struct da9063_irq_data {
u16 reg;
u8 mask;
};
static const struct regmap_irq da9063_irqs[] = {
/* DA9063 event A register */
......
......@@ -33,25 +33,25 @@
* This driver was tested with firmware revision A4.
*/
#if defined(CONFIG_INPUT_DM355EVM) || defined(CONFIG_INPUT_DM355EVM_MODULE)
#if IS_ENABLED(CONFIG_INPUT_DM355EVM)
#define msp_has_keyboard() true
#else
#define msp_has_keyboard() false
#endif
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
#if IS_ENABLED(CONFIG_LEDS_GPIO)
#define msp_has_leds() true
#else
#define msp_has_leds() false
#endif
#if defined(CONFIG_RTC_DRV_DM355EVM) || defined(CONFIG_RTC_DRV_DM355EVM_MODULE)
#if IS_ENABLED(CONFIG_RTC_DRV_DM355EVM)
#define msp_has_rtc() true
#else
#define msp_has_rtc() false
#endif
#if defined(CONFIG_VIDEO_TVP514X) || defined(CONFIG_VIDEO_TVP514X_MODULE)
#if IS_ENABLED(CONFIG_VIDEO_TVP514X)
#define msp_has_tvp() true
#else
#define msp_has_tvp() false
......@@ -260,7 +260,7 @@ static int add_children(struct i2c_client *client)
/* GPIO-ish stuff */
dm355evm_msp_gpio.parent = &client->dev;
status = gpiochip_add(&dm355evm_msp_gpio);
status = gpiochip_add_data(&dm355evm_msp_gpio, NULL);
if (status < 0)
return status;
......
......@@ -76,7 +76,7 @@ static int hi6421_pmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pmic);
ret = mfd_add_devices(&pdev->dev, 0, hi6421_devs,
ret = devm_mfd_add_devices(&pdev->dev, 0, hi6421_devs,
ARRAY_SIZE(hi6421_devs), NULL, 0, NULL);
if (ret) {
dev_err(&pdev->dev, "add mfd devices failed: %d\n", ret);
......@@ -86,13 +86,6 @@ static int hi6421_pmic_probe(struct platform_device *pdev)
return 0;
}
static int hi6421_pmic_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
return 0;
}
static const struct of_device_id of_hi6421_pmic_match_tbl[] = {
{ .compatible = "hisilicon,hi6421-pmic", },
{ },
......@@ -105,7 +98,6 @@ static struct platform_driver hi6421_pmic_driver = {
.of_match_table = of_hi6421_pmic_match_tbl,
},
.probe = hi6421_pmic_probe,
.remove = hi6421_pmic_remove,
};
module_platform_driver(hi6421_pmic_driver);
......
/*
* Device driver for MFD hi655x PMIC
*
* Copyright (c) 2016 Hisilicon.
*
* Authors:
* Chen Feng <puck.chen@hisilicon.com>
* Fei Wang <w.f@huawei.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.
*/
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/mfd/core.h>
#include <linux/mfd/hi655x-pmic.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
static const struct mfd_cell hi655x_pmic_devs[] = {
{ .name = "hi655x-regulator", },
};
static const struct regmap_irq hi655x_irqs[] = {
{ .reg_offset = 0, .mask = OTMP_D1R_INT },
{ .reg_offset = 0, .mask = VSYS_2P5_R_INT },
{ .reg_offset = 0, .mask = VSYS_UV_D3R_INT },
{ .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT },
{ .reg_offset = 0, .mask = PWRON_D4SR_INT },
{ .reg_offset = 0, .mask = PWRON_D20F_INT },
{ .reg_offset = 0, .mask = PWRON_D20R_INT },
{ .reg_offset = 0, .mask = RESERVE_INT },
};
static const struct regmap_irq_chip hi655x_irq_chip = {
.name = "hi655x-pmic",
.irqs = hi655x_irqs,
.num_regs = 1,
.num_irqs = ARRAY_SIZE(hi655x_irqs),
.status_base = HI655X_IRQ_STAT_BASE,
.mask_base = HI655X_IRQ_MASK_BASE,
};
static struct regmap_config hi655x_regmap_config = {
.reg_bits = 32,
.reg_stride = HI655X_STRIDE,
.val_bits = 8,
.max_register = HI655X_BUS_ADDR(0xFFF),
};
static void hi655x_local_irq_clear(struct regmap *map)
{
int i;
regmap_write(map, HI655X_ANA_IRQM_BASE, HI655X_IRQ_CLR);
for (i = 0; i < HI655X_IRQ_ARRAY; i++) {
regmap_write(map, HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE,
HI655X_IRQ_CLR);
}
}
static int hi655x_pmic_probe(struct platform_device *pdev)
{
int ret;
struct hi655x_pmic *pmic;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
void __iomem *base;
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
pmic->dev = dev;
pmic->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!pmic->res)
return -ENOENT;
base = devm_ioremap_resource(dev, pmic->res);
if (!base)
return -ENOMEM;
pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
&hi655x_regmap_config);
regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver);
if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) {
dev_warn(dev, "PMU version %d unsupported\n", pmic->ver);
return -EINVAL;
}
hi655x_local_irq_clear(pmic->regmap);
pmic->gpio = of_get_named_gpio(np, "pmic-gpios", 0);
if (!gpio_is_valid(pmic->gpio)) {
dev_err(dev, "Failed to get the pmic-gpios\n");
return -ENODEV;
}
ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN,
"hi655x_pmic_irq");
if (ret < 0) {
dev_err(dev, "Failed to request gpio %d ret = %d\n",
pmic->gpio, ret);
return ret;
}
ret = regmap_add_irq_chip(pmic->regmap, gpio_to_irq(pmic->gpio),
IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0,
&hi655x_irq_chip, &pmic->irq_data);
if (ret) {
dev_err(dev, "Failed to obtain 'hi655x_pmic_irq' %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, pmic);
ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, hi655x_pmic_devs,
ARRAY_SIZE(hi655x_pmic_devs), NULL, 0, NULL);
if (ret) {
dev_err(dev, "Failed to register device %d\n", ret);
regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data);
return ret;
}
return 0;
}
static int hi655x_pmic_remove(struct platform_device *pdev)
{
struct hi655x_pmic *pmic = platform_get_drvdata(pdev);
regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data);
mfd_remove_devices(&pdev->dev);
return 0;
}
static const struct of_device_id hi655x_pmic_match[] = {
{ .compatible = "hisilicon,hi655x-pmic", },
{},
};
static struct platform_driver hi655x_pmic_driver = {
.driver = {
.name = "hi655x-pmic",
.of_match_table = of_match_ptr(hi655x_pmic_match),
},
.probe = hi655x_pmic_probe,
.remove = hi655x_pmic_remove,
};
module_platform_driver(hi655x_pmic_driver);
MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
MODULE_DESCRIPTION("Hisilicon hi655x PMIC driver");
MODULE_LICENSE("GPL v2");
......@@ -155,7 +155,7 @@ static int egpio_get(struct gpio_chip *chip, unsigned offset)
pr_debug("egpio_get_value(%d)\n", chip->base + offset);
egpio = container_of(chip, struct egpio_chip, chip);
egpio = gpiochip_get_data(chip);
ei = dev_get_drvdata(egpio->dev);
bit = egpio_bit(ei, offset);
reg = egpio->reg_start + egpio_pos(ei, offset);
......@@ -170,7 +170,7 @@ static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct egpio_chip *egpio;
egpio = container_of(chip, struct egpio_chip, chip);
egpio = gpiochip_get_data(chip);
return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
}
......@@ -192,7 +192,7 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
pr_debug("egpio_set(%s, %d(%d), %d)\n",
chip->label, offset, offset+chip->base, value);
egpio = container_of(chip, struct egpio_chip, chip);
egpio = gpiochip_get_data(chip);
ei = dev_get_drvdata(egpio->dev);
bit = egpio_bit(ei, offset);
pos = egpio_pos(ei, offset);
......@@ -216,7 +216,7 @@ static int egpio_direction_output(struct gpio_chip *chip,
{
struct egpio_chip *egpio;
egpio = container_of(chip, struct egpio_chip, chip);
egpio = gpiochip_get_data(chip);
if (test_bit(offset, &egpio->is_out)) {
egpio_set(chip, offset, value);
return 0;
......@@ -330,7 +330,7 @@ static int __init egpio_probe(struct platform_device *pdev)
chip->base = pdata->chip[i].gpio_base;
chip->ngpio = pdata->chip[i].num_gpios;
gpiochip_add(chip);
gpiochip_add_data(chip, &ei->chip[i]);
}
/* Set initial pin values */
......
......@@ -227,8 +227,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct i2c_client *client;
struct htcpld_chip *chip_data =
container_of(chip, struct htcpld_chip, chip_out);
struct htcpld_chip *chip_data = gpiochip_get_data(chip);
unsigned long flags;
client = chip_data->client;
......@@ -257,14 +256,12 @@ static void htcpld_chip_set_ni(struct work_struct *work)
static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
struct htcpld_chip *chip_data = gpiochip_get_data(chip);
u8 cache;
if (!strncmp(chip->label, "htcpld-out", 10)) {
chip_data = container_of(chip, struct htcpld_chip, chip_out);
cache = chip_data->cache_out;
} else if (!strncmp(chip->label, "htcpld-in", 9)) {
chip_data = container_of(chip, struct htcpld_chip, chip_in);
cache = chip_data->cache_in;
} else
return -EINVAL;
......@@ -291,9 +288,7 @@ static int htcpld_direction_input(struct gpio_chip *chip,
static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
chip_data = container_of(chip, struct htcpld_chip, chip_in);
struct htcpld_chip *chip_data = gpiochip_get_data(chip);
if (offset < chip_data->nirqs)
return chip_data->irq_start + offset;
......@@ -451,14 +446,14 @@ static int htcpld_register_chip_gpio(
gpio_chip->ngpio = plat_chip_data->num_gpios;
/* Add the GPIO chips */
ret = gpiochip_add(&(chip->chip_out));
ret = gpiochip_add_data(&(chip->chip_out), chip);
if (ret) {
dev_warn(dev, "Unable to register output GPIOs for 0x%x: %d\n",
plat_chip_data->addr, ret);
return ret;
}
ret = gpiochip_add(&(chip->chip_in));
ret = gpiochip_add_data(&(chip->chip_in), chip);
if (ret) {
dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n",
plat_chip_data->addr, ret);
......
......@@ -34,6 +34,7 @@
#define LPSS_DEV_SIZE 0x200
#define LPSS_PRIV_OFFSET 0x200
#define LPSS_PRIV_SIZE 0x100
#define LPSS_PRIV_REG_COUNT (LPSS_PRIV_SIZE / 4)
#define LPSS_IDMA64_OFFSET 0x800
#define LPSS_IDMA64_SIZE 0x800
......@@ -76,6 +77,7 @@ struct intel_lpss {
struct mfd_cell *cell;
struct device *dev;
void __iomem *priv;
u32 priv_ctx[LPSS_PRIV_REG_COUNT];
int devid;
u32 caps;
u32 active_ltr;
......@@ -336,8 +338,8 @@ static int intel_lpss_register_clock(struct intel_lpss *lpss)
return 0;
/* Root clock */
clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL,
CLK_IS_ROOT, lpss->info->clk_rate);
clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, 0,
lpss->info->clk_rate);
if (IS_ERR(clk))
return PTR_ERR(clk);
......@@ -493,6 +495,16 @@ EXPORT_SYMBOL_GPL(intel_lpss_prepare);
int intel_lpss_suspend(struct device *dev)
{
struct intel_lpss *lpss = dev_get_drvdata(dev);
unsigned int i;
/* Save device context */
for (i = 0; i < LPSS_PRIV_REG_COUNT; i++)
lpss->priv_ctx[i] = readl(lpss->priv + i * 4);
/* Put the device into reset state */
writel(0, lpss->priv + LPSS_PRIV_RESETS);
return 0;
}
EXPORT_SYMBOL_GPL(intel_lpss_suspend);
......@@ -500,8 +512,13 @@ EXPORT_SYMBOL_GPL(intel_lpss_suspend);
int intel_lpss_resume(struct device *dev)
{
struct intel_lpss *lpss = dev_get_drvdata(dev);
unsigned int i;
intel_lpss_init_dev(lpss);
intel_lpss_deassert_reset(lpss);
/* Restore device context */
for (i = 0; i < LPSS_PRIV_REG_COUNT; i++)
writel(lpss->priv_ctx[i], lpss->priv + i * 4);
return 0;
}
......
......@@ -53,7 +53,7 @@
#define INTEL_QUARK_I2C_CLK_HZ 33000000
struct intel_quark_mfd {
struct pci_dev *pdev;
struct device *dev;
struct clk *i2c_clk;
struct clk_lookup *i2c_clk_lookup;
};
......@@ -123,14 +123,14 @@ static const struct pci_device_id intel_quark_mfd_ids[] = {
};
MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids);
static int intel_quark_register_i2c_clk(struct intel_quark_mfd *quark_mfd)
static int intel_quark_register_i2c_clk(struct device *dev)
{
struct pci_dev *pdev = quark_mfd->pdev;
struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
struct clk *i2c_clk;
i2c_clk = clk_register_fixed_rate(&pdev->dev,
i2c_clk = clk_register_fixed_rate(dev,
INTEL_QUARK_I2C_CONTROLLER_CLK, NULL,
CLK_IS_ROOT, INTEL_QUARK_I2C_CLK_HZ);
0, INTEL_QUARK_I2C_CLK_HZ);
if (IS_ERR(i2c_clk))
return PTR_ERR(i2c_clk);
......@@ -139,18 +139,19 @@ static int intel_quark_register_i2c_clk(struct intel_quark_mfd *quark_mfd)
INTEL_QUARK_I2C_CONTROLLER_CLK);
if (!quark_mfd->i2c_clk_lookup) {
dev_err(&pdev->dev, "Fixed clk register failed\n");
clk_unregister(quark_mfd->i2c_clk);
dev_err(dev, "Fixed clk register failed\n");
return -ENOMEM;
}
return 0;
}
static void intel_quark_unregister_i2c_clk(struct pci_dev *pdev)
static void intel_quark_unregister_i2c_clk(struct device *dev)
{
struct intel_quark_mfd *quark_mfd = dev_get_drvdata(&pdev->dev);
struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
if (!quark_mfd->i2c_clk || !quark_mfd->i2c_clk_lookup)
if (!quark_mfd->i2c_clk_lookup)
return;
clkdev_drop(quark_mfd->i2c_clk_lookup);
......@@ -245,30 +246,38 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev,
quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL);
if (!quark_mfd)
return -ENOMEM;
quark_mfd->pdev = pdev;
ret = intel_quark_register_i2c_clk(quark_mfd);
quark_mfd->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, quark_mfd);
ret = intel_quark_register_i2c_clk(&pdev->dev);
if (ret)
return ret;
dev_set_drvdata(&pdev->dev, quark_mfd);
ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]);
if (ret)
return ret;
goto err_unregister_i2c_clk;
ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]);
if (ret)
return ret;
goto err_unregister_i2c_clk;
return mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells,
ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells,
ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0,
NULL);
if (ret)
goto err_unregister_i2c_clk;
return 0;
err_unregister_i2c_clk:
intel_quark_unregister_i2c_clk(&pdev->dev);
return ret;
}
static void intel_quark_mfd_remove(struct pci_dev *pdev)
{
intel_quark_unregister_i2c_clk(pdev);
intel_quark_unregister_i2c_clk(&pdev->dev);
mfd_remove_devices(&pdev->dev);
}
......
......@@ -35,6 +35,7 @@ static struct gpiod_lookup_table panel_gpio_table = {
.table = {
/* Panel EN/DISABLE */
GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH),
{ },
},
};
......
......@@ -123,18 +123,11 @@ static int lp3943_probe(struct i2c_client *cl, const struct i2c_device_id *id)
lp3943->mux_cfg = lp3943_mux_cfg;
i2c_set_clientdata(cl, lp3943);
return mfd_add_devices(dev, -1, lp3943_devs, ARRAY_SIZE(lp3943_devs),
return devm_mfd_add_devices(dev, -1, lp3943_devs,
ARRAY_SIZE(lp3943_devs),
NULL, 0, NULL);
}
static int lp3943_remove(struct i2c_client *cl)
{
struct lp3943 *lp3943 = i2c_get_clientdata(cl);
mfd_remove_devices(lp3943->dev);
return 0;
}
static const struct i2c_device_id lp3943_ids[] = {
{ "lp3943", 0 },
{ }
......@@ -151,7 +144,6 @@ MODULE_DEVICE_TABLE(of, lp3943_of_match);
static struct i2c_driver lp3943_driver = {
.probe = lp3943_probe,
.remove = lp3943_remove,
.driver = {
.name = "lp3943",
.of_match_table = of_match_ptr(lp3943_of_match),
......
......@@ -112,7 +112,7 @@ static irqreturn_t lp8788_irq_handler(int irq, void *ptr)
struct lp8788_irq_data *irqd = ptr;
struct lp8788 *lp = irqd->lp;
u8 status[NUM_REGS], addr, mask;
bool handled;
bool handled = false;
int i;
if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS))
......
/*
* Maxim MAX77620 MFD Driver
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Laxman Dewangan <ldewangan@nvidia.com>
* Chaitanya Bandi <bandik@nvidia.com>
* Mallikarjun Kasoju <mkasoju@nvidia.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.
*/
/****************** Teminology used in driver ********************
* Here are some terminology used from datasheet for quick reference:
* Flexible Power Sequence (FPS):
* The Flexible Power Sequencer (FPS) allows each regulator to power up under
* hardware or software control. Additionally, each regulator can power on
* independently or among a group of other regulators with an adjustable
* power-up and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can
* be programmed to be part of a sequence allowing external regulators to be
* sequenced along with internal regulators. 32KHz clock can be programmed to
* be part of a sequence.
* There is 3 FPS confguration registers and all resources are configured to
* any of these FPS or no FPS.
*/
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max77620.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
static struct resource gpio_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO),
};
static struct resource power_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_LBT_MBATLOW),
};
static struct resource rtc_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_TOP_RTC),
};
static struct resource thermal_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM1),
DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM2),
};
static const struct regmap_irq max77620_top_irqs[] = {
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GLBL, 0, MAX77620_IRQ_TOP_GLBL_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_SD, 0, MAX77620_IRQ_TOP_SD_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_LDO, 0, MAX77620_IRQ_TOP_LDO_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GPIO, 0, MAX77620_IRQ_TOP_GPIO_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_RTC, 0, MAX77620_IRQ_TOP_RTC_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_32K, 0, MAX77620_IRQ_TOP_32K_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_ONOFF, 0, MAX77620_IRQ_TOP_ONOFF_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_LBT_MBATLOW, 1, MAX77620_IRQ_LBM_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM1, 1, MAX77620_IRQ_TJALRM1_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM2, 1, MAX77620_IRQ_TJALRM2_MASK),
};
static const struct mfd_cell max77620_children[] = {
{ .name = "max77620-pinctrl", },
{ .name = "max77620-clock", },
{ .name = "max77620-pmic", },
{ .name = "max77620-watchdog", },
{
.name = "max77620-gpio",
.resources = gpio_resources,
.num_resources = ARRAY_SIZE(gpio_resources),
}, {
.name = "max77620-rtc",
.resources = rtc_resources,
.num_resources = ARRAY_SIZE(rtc_resources),
}, {
.name = "max77620-power",
.resources = power_resources,
.num_resources = ARRAY_SIZE(power_resources),
}, {
.name = "max77620-thermal",
.resources = thermal_resources,
.num_resources = ARRAY_SIZE(thermal_resources),
},
};
static const struct mfd_cell max20024_children[] = {
{ .name = "max20024-pinctrl", },
{ .name = "max77620-clock", },
{ .name = "max20024-pmic", },
{ .name = "max77620-watchdog", },
{
.name = "max77620-gpio",
.resources = gpio_resources,
.num_resources = ARRAY_SIZE(gpio_resources),
}, {
.name = "max77620-rtc",
.resources = rtc_resources,
.num_resources = ARRAY_SIZE(rtc_resources),
}, {
.name = "max20024-power",
.resources = power_resources,
.num_resources = ARRAY_SIZE(power_resources),
},
};
static struct regmap_irq_chip max77620_top_irq_chip = {
.name = "max77620-top",
.irqs = max77620_top_irqs,
.num_irqs = ARRAY_SIZE(max77620_top_irqs),
.num_regs = 2,
.status_base = MAX77620_REG_IRQTOP,
.mask_base = MAX77620_REG_IRQTOPM,
};
static const struct regmap_range max77620_readable_ranges[] = {
regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4),
};
static const struct regmap_access_table max77620_readable_table = {
.yes_ranges = max77620_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(max77620_readable_ranges),
};
static const struct regmap_range max20024_readable_ranges[] = {
regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4),
regmap_reg_range(MAX20024_REG_MAX_ADD, MAX20024_REG_MAX_ADD),
};
static const struct regmap_access_table max20024_readable_table = {
.yes_ranges = max20024_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(max20024_readable_ranges),
};
static const struct regmap_range max77620_writable_ranges[] = {
regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4),
};
static const struct regmap_access_table max77620_writable_table = {
.yes_ranges = max77620_writable_ranges,
.n_yes_ranges = ARRAY_SIZE(max77620_writable_ranges),
};
static const struct regmap_range max77620_cacheable_ranges[] = {
regmap_reg_range(MAX77620_REG_SD0_CFG, MAX77620_REG_LDO_CFG3),
regmap_reg_range(MAX77620_REG_FPS_CFG0, MAX77620_REG_FPS_SD3),
};
static const struct regmap_access_table max77620_volatile_table = {
.no_ranges = max77620_cacheable_ranges,
.n_no_ranges = ARRAY_SIZE(max77620_cacheable_ranges),
};
static const struct regmap_config max77620_regmap_config = {
.name = "power-slave",
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX77620_REG_DVSSD4 + 1,
.cache_type = REGCACHE_RBTREE,
.rd_table = &max77620_readable_table,
.wr_table = &max77620_writable_table,
.volatile_table = &max77620_volatile_table,
};
static const struct regmap_config max20024_regmap_config = {
.name = "power-slave",
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX20024_REG_MAX_ADD + 1,
.cache_type = REGCACHE_RBTREE,
.rd_table = &max20024_readable_table,
.wr_table = &max77620_writable_table,
.volatile_table = &max77620_volatile_table,
};
/* max77620_get_fps_period_reg_value: Get FPS bit field value from
* requested periods.
* MAX77620 supports the FPS period of 40, 80, 160, 320, 540, 1280, 2560
* and 5120 microseconds. MAX20024 supports the FPS period of 20, 40, 80,
* 160, 320, 540, 1280 and 2560 microseconds.
* The FPS register has 3 bits field to set the FPS period as
* bits max77620 max20024
* 000 40 20
* 001 80 40
* :::
*/
static int max77620_get_fps_period_reg_value(struct max77620_chip *chip,
int tperiod)
{
int fps_min_period;
int i;
switch (chip->chip_id) {
case MAX20024:
fps_min_period = MAX20024_FPS_PERIOD_MIN_US;
break;
case MAX77620:
fps_min_period = MAX77620_FPS_PERIOD_MIN_US;
default:
return -EINVAL;
}
for (i = 0; i < 7; i++) {
if (fps_min_period >= tperiod)
return i;
fps_min_period *= 2;
}
return i;
}
/* max77620_config_fps: Configure FPS configuration registers
* based on platform specific information.
*/
static int max77620_config_fps(struct max77620_chip *chip,
struct device_node *fps_np)
{
struct device *dev = chip->dev;
unsigned int mask = 0, config = 0;
u32 fps_max_period;
u32 param_val;
int tperiod, fps_id;
int ret;
char fps_name[10];
switch (chip->chip_id) {
case MAX20024:
fps_max_period = MAX20024_FPS_PERIOD_MAX_US;
break;
case MAX77620:
fps_max_period = MAX77620_FPS_PERIOD_MAX_US;
default:
return -EINVAL;
}
for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) {
sprintf(fps_name, "fps%d", fps_id);
if (!strcmp(fps_np->name, fps_name))
break;
}
if (fps_id == MAX77620_FPS_COUNT) {
dev_err(dev, "FPS node name %s is not valid\n", fps_np->name);
return -EINVAL;
}
ret = of_property_read_u32(fps_np, "maxim,shutdown-fps-time-period-us",
&param_val);
if (!ret) {
mask |= MAX77620_FPS_TIME_PERIOD_MASK;
chip->shutdown_fps_period[fps_id] = min(param_val,
fps_max_period);
tperiod = max77620_get_fps_period_reg_value(chip,
chip->shutdown_fps_period[fps_id]);
config |= tperiod << MAX77620_FPS_TIME_PERIOD_SHIFT;
}
ret = of_property_read_u32(fps_np, "maxim,suspend-fps-time-period-us",
&param_val);
if (!ret)
chip->suspend_fps_period[fps_id] = min(param_val,
fps_max_period);
ret = of_property_read_u32(fps_np, "maxim,fps-event-source",
&param_val);
if (!ret) {
if (param_val > 2) {
dev_err(dev, "FPS%d event-source invalid\n", fps_id);
return -EINVAL;
}
mask |= MAX77620_FPS_EN_SRC_MASK;
config |= param_val << MAX77620_FPS_EN_SRC_SHIFT;
if (param_val == 2) {
mask |= MAX77620_FPS_ENFPS_SW_MASK;
config |= MAX77620_FPS_ENFPS_SW;
}
}
if (!chip->sleep_enable && !chip->enable_global_lpm) {
ret = of_property_read_u32(fps_np,
"maxim,device-state-on-disabled-event",
&param_val);
if (!ret) {
if (param_val == 0)
chip->sleep_enable = true;
else if (param_val == 1)
chip->enable_global_lpm = true;
}
}
ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id,
mask, config);
if (ret < 0) {
dev_err(dev, "Failed to update FPS CFG: %d\n", ret);
return ret;
}
return 0;
}
static int max77620_initialise_fps(struct max77620_chip *chip)
{
struct device *dev = chip->dev;
struct device_node *fps_np, *fps_child;
u8 config;
int fps_id;
int ret;
for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) {
chip->shutdown_fps_period[fps_id] = -1;
chip->suspend_fps_period[fps_id] = -1;
}
fps_np = of_get_child_by_name(dev->of_node, "fps");
if (!fps_np)
goto skip_fps;
for_each_child_of_node(fps_np, fps_child) {
ret = max77620_config_fps(chip, fps_child);
if (ret < 0)
return ret;
}
config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0;
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
MAX77620_ONOFFCNFG2_SLP_LPM_MSK, config);
if (ret < 0) {
dev_err(dev, "Failed to update SLP_LPM: %d\n", ret);
return ret;
}
skip_fps:
/* Enable wake on EN0 pin */
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
MAX77620_ONOFFCNFG2_WK_EN0,
MAX77620_ONOFFCNFG2_WK_EN0);
if (ret < 0) {
dev_err(dev, "Failed to update WK_EN0: %d\n", ret);
return ret;
}
/* For MAX20024, SLPEN will be POR reset if CLRSE is b11 */
if ((chip->chip_id == MAX20024) && chip->sleep_enable) {
config = MAX77620_ONOFFCNFG1_SLPEN | MAX20024_ONOFFCNFG1_CLRSE;
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1,
config, config);
if (ret < 0) {
dev_err(dev, "Failed to update SLPEN: %d\n", ret);
return ret;
}
}
return 0;
}
static int max77620_read_es_version(struct max77620_chip *chip)
{
unsigned int val;
u8 cid_val[6];
int i;
int ret;
for (i = MAX77620_REG_CID0; i <= MAX77620_REG_CID5; i++) {
ret = regmap_read(chip->rmap, i, &val);
if (ret < 0) {
dev_err(chip->dev, "Failed to read CID: %d\n", ret);
return ret;
}
dev_dbg(chip->dev, "CID%d: 0x%02x\n",
i - MAX77620_REG_CID0, val);
cid_val[i - MAX77620_REG_CID0] = val;
}
/* CID4 is OTP Version and CID5 is ES version */
dev_info(chip->dev, "PMIC Version OTP:0x%02X and ES:0x%X\n",
cid_val[4], MAX77620_CID5_DIDM(cid_val[5]));
return ret;
}
static int max77620_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct regmap_config *rmap_config;
struct max77620_chip *chip;
const struct mfd_cell *mfd_cells;
int n_mfd_cells;
int ret;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
i2c_set_clientdata(client, chip);
chip->dev = &client->dev;
chip->irq_base = -1;
chip->chip_irq = client->irq;
chip->chip_id = (enum max77620_chip_id)id->driver_data;
switch (chip->chip_id) {
case MAX77620:
mfd_cells = max77620_children;
n_mfd_cells = ARRAY_SIZE(max77620_children);
rmap_config = &max77620_regmap_config;
break;
case MAX20024:
mfd_cells = max20024_children;
n_mfd_cells = ARRAY_SIZE(max20024_children);
rmap_config = &max20024_regmap_config;
break;
default:
dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id);
return -EINVAL;
}
chip->rmap = devm_regmap_init_i2c(client, rmap_config);
if (IS_ERR(chip->rmap)) {
ret = PTR_ERR(chip->rmap);
dev_err(chip->dev, "Failed to intialise regmap: %d\n", ret);
return ret;
}
ret = max77620_read_es_version(chip);
if (ret < 0)
return ret;
ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq,
IRQF_ONESHOT | IRQF_SHARED,
chip->irq_base, &max77620_top_irq_chip,
&chip->top_irq_data);
if (ret < 0) {
dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret);
return ret;
}
ret = max77620_initialise_fps(chip);
if (ret < 0)
return ret;
ret = devm_mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE,
mfd_cells, n_mfd_cells, NULL, 0,
regmap_irq_get_domain(chip->top_irq_data));
if (ret < 0) {
dev_err(chip->dev, "Failed to add MFD children: %d\n", ret);
return ret;
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int max77620_set_fps_period(struct max77620_chip *chip,
int fps_id, int time_period)
{
int period = max77620_get_fps_period_reg_value(chip, time_period);
int ret;
ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id,
MAX77620_FPS_TIME_PERIOD_MASK,
period << MAX77620_FPS_TIME_PERIOD_SHIFT);
if (ret < 0) {
dev_err(chip->dev, "Failed to update FPS period: %d\n", ret);
return ret;
}
return 0;
}
static int max77620_i2c_suspend(struct device *dev)
{
struct max77620_chip *chip = dev_get_drvdata(dev);
struct i2c_client *client = to_i2c_client(dev);
unsigned int config;
int fps;
int ret;
for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) {
if (chip->suspend_fps_period[fps] < 0)
continue;
ret = max77620_set_fps_period(chip, fps,
chip->suspend_fps_period[fps]);
if (ret < 0)
return ret;
}
/*
* For MAX20024: No need to configure SLPEN on suspend as
* it will be configured on Init.
*/
if (chip->chip_id == MAX20024)
goto out;
config = (chip->sleep_enable) ? MAX77620_ONOFFCNFG1_SLPEN : 0;
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1,
MAX77620_ONOFFCNFG1_SLPEN,
config);
if (ret < 0) {
dev_err(dev, "Failed to configure sleep in suspend: %d\n", ret);
return ret;
}
/* Disable WK_EN0 */
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
MAX77620_ONOFFCNFG2_WK_EN0, 0);
if (ret < 0) {
dev_err(dev, "Failed to configure WK_EN in suspend: %d\n", ret);
return ret;
}
out:
disable_irq(client->irq);
return 0;
}
static int max77620_i2c_resume(struct device *dev)
{
struct max77620_chip *chip = dev_get_drvdata(dev);
struct i2c_client *client = to_i2c_client(dev);
int ret;
int fps;
for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) {
if (chip->shutdown_fps_period[fps] < 0)
continue;
ret = max77620_set_fps_period(chip, fps,
chip->shutdown_fps_period[fps]);
if (ret < 0)
return ret;
}
/*
* For MAX20024: No need to configure WKEN0 on resume as
* it is configured on Init.
*/
if (chip->chip_id == MAX20024)
goto out;
/* Enable WK_EN0 */
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
MAX77620_ONOFFCNFG2_WK_EN0,
MAX77620_ONOFFCNFG2_WK_EN0);
if (ret < 0) {
dev_err(dev, "Failed to configure WK_EN0 n resume: %d\n", ret);
return ret;
}
out:
enable_irq(client->irq);
return 0;
}
#endif
static const struct i2c_device_id max77620_id[] = {
{"max77620", MAX77620},
{"max20024", MAX20024},
{},
};
MODULE_DEVICE_TABLE(i2c, max77620_id);
static const struct dev_pm_ops max77620_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max77620_i2c_suspend, max77620_i2c_resume)
};
static struct i2c_driver max77620_driver = {
.driver = {
.name = "max77620",
.pm = &max77620_pm_ops,
},
.probe = max77620_probe,
.id_table = max77620_id,
};
module_i2c_driver(max77620_driver);
MODULE_DESCRIPTION("MAX77620/MAX20024 Multi Function Device Core Driver");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>");
MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>");
MODULE_LICENSE("GPL v2");
......@@ -2,7 +2,7 @@
* max77686.c - mfd core driver for the Maxim 77686/802
*
* Copyright (C) 2012 Samsung Electronics
* Chiwoong Byun <woong.byun@smasung.com>
* Chiwoong Byun <woong.byun@samsung.com>
* Jonghwa Lee <jonghwa3.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -230,7 +230,8 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
return -ENODEV;
}
ret = regmap_add_irq_chip(max77686->regmap, max77686->irq,
ret = devm_regmap_add_irq_chip(&i2c->dev, max77686->regmap,
max77686->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
IRQF_SHARED, 0, irq_chip,
&max77686->irq_data);
......@@ -239,27 +240,12 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL, 0, NULL);
ret = devm_mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL,
0, NULL);
if (ret < 0) {
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
goto err_del_irqc;
}
return 0;
err_del_irqc:
regmap_del_irq_chip(max77686->irq, max77686->irq_data);
return ret;
}
static int max77686_i2c_remove(struct i2c_client *i2c)
{
struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
mfd_remove_devices(max77686->dev);
regmap_del_irq_chip(max77686->irq, max77686->irq_data);
}
return 0;
}
......@@ -317,22 +303,10 @@ static struct i2c_driver max77686_i2c_driver = {
.of_match_table = of_match_ptr(max77686_pmic_dt_match),
},
.probe = max77686_i2c_probe,
.remove = max77686_i2c_remove,
.id_table = max77686_i2c_id,
};
static int __init max77686_i2c_init(void)
{
return i2c_add_driver(&max77686_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(max77686_i2c_init);
static void __exit max77686_i2c_exit(void)
{
i2c_del_driver(&max77686_i2c_driver);
}
module_exit(max77686_i2c_exit);
module_i2c_driver(max77686_i2c_driver);
MODULE_DESCRIPTION("MAXIM 77686/802 multi-function core driver");
MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
......
......@@ -2,7 +2,7 @@
* max77693.c - mfd core driver for the MAX 77693
*
* Copyright (C) 2012 Samsung Electronics
* SangYoung Son <hello.son@smasung.com>
* SangYoung Son <hello.son@samsung.com>
*
* This program is not provided / owned by Maxim Integrated Products.
*
......@@ -368,6 +368,7 @@ static const struct of_device_id max77693_dt_match[] = {
{ .compatible = "maxim,max77693" },
{},
};
MODULE_DEVICE_TABLE(of, max77693_dt_match);
#endif
static struct i2c_driver max77693_i2c_driver = {
......@@ -381,18 +382,7 @@ static struct i2c_driver max77693_i2c_driver = {
.id_table = max77693_i2c_id,
};
static int __init max77693_i2c_init(void)
{
return i2c_add_driver(&max77693_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(max77693_i2c_init);
static void __exit max77693_i2c_exit(void)
{
i2c_del_driver(&max77693_i2c_driver);
}
module_exit(max77693_i2c_exit);
module_i2c_driver(max77693_i2c_driver);
MODULE_DESCRIPTION("MAXIM 77693 multi-function core driver");
MODULE_AUTHOR("SangYoung, Son <hello.son@samsung.com>");
......
......@@ -96,7 +96,7 @@ menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids)
return ret;
}
ret = mfd_add_devices(&client->dev, 0, menf21bmc_cell,
ret = devm_mfd_add_devices(&client->dev, 0, menf21bmc_cell,
ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL);
if (ret < 0) {
dev_err(&client->dev, "failed to add BMC sub-devices\n");
......@@ -106,12 +106,6 @@ menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids)
return 0;
}
static int menf21bmc_remove(struct i2c_client *client)
{
mfd_remove_devices(&client->dev);
return 0;
}
static const struct i2c_device_id menf21bmc_id_table[] = {
{ "menf21bmc" },
{ }
......@@ -122,7 +116,6 @@ static struct i2c_driver menf21bmc_driver = {
.driver.name = "menf21bmc",
.id_table = menf21bmc_id_table,
.probe = menf21bmc_probe,
.remove = menf21bmc_remove,
};
module_i2c_driver(menf21bmc_driver);
......
......@@ -107,7 +107,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
list_for_each_entry(child, &parent->children, node) {
if (acpi_match_device_ids(child, ids)) {
if (!acpi_match_device_ids(child, ids)) {
adev = child;
break;
}
......@@ -334,6 +334,44 @@ void mfd_remove_devices(struct device *parent)
}
EXPORT_SYMBOL(mfd_remove_devices);
static void devm_mfd_dev_release(struct device *dev, void *res)
{
mfd_remove_devices(dev);
}
/**
* devm_mfd_add_devices - Resource managed version of mfd_add_devices()
*
* Returns 0 on success or an appropriate negative error number on failure.
* All child-devices of the MFD will automatically be removed when it gets
* unbinded.
*/
int devm_mfd_add_devices(struct device *dev, int id,
const struct mfd_cell *cells, int n_devs,
struct resource *mem_base,
int irq_base, struct irq_domain *domain)
{
struct device **ptr;
int ret;
ptr = devres_alloc(devm_mfd_dev_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = mfd_add_devices(dev, id, cells, n_devs, mem_base,
irq_base, domain);
if (ret < 0) {
devres_free(ptr);
return ret;
}
*ptr = dev;
devres_add(dev, ptr);
return ret;
}
EXPORT_SYMBOL(devm_mfd_add_devices);
int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones)
{
struct mfd_cell cell_entry;
......
......@@ -267,17 +267,26 @@ static int mt6397_probe(struct platform_device *pdev)
ret = regmap_read(pmic->regmap, MT6397_CID, &id);
if (ret) {
dev_err(pmic->dev, "Failed to read chip id: %d\n", ret);
goto fail_irq;
return ret;
}
pmic->irq = platform_get_irq(pdev, 0);
if (pmic->irq <= 0)
return pmic->irq;
switch (id & 0xff) {
case MT6323_CID_CODE:
pmic->int_con[0] = MT6323_INT_CON0;
pmic->int_con[1] = MT6323_INT_CON1;
pmic->int_status[0] = MT6323_INT_STATUS0;
pmic->int_status[1] = MT6323_INT_STATUS1;
ret = mfd_add_devices(&pdev->dev, -1, mt6323_devs,
ARRAY_SIZE(mt6323_devs), NULL, 0, NULL);
ret = mt6397_irq_init(pmic);
if (ret)
return ret;
ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs,
ARRAY_SIZE(mt6323_devs), NULL,
0, NULL);
break;
case MT6397_CID_CODE:
......@@ -286,8 +295,13 @@ static int mt6397_probe(struct platform_device *pdev)
pmic->int_con[1] = MT6397_INT_CON1;
pmic->int_status[0] = MT6397_INT_STATUS0;
pmic->int_status[1] = MT6397_INT_STATUS1;
ret = mfd_add_devices(&pdev->dev, -1, mt6397_devs,
ARRAY_SIZE(mt6397_devs), NULL, 0, NULL);
ret = mt6397_irq_init(pmic);
if (ret)
return ret;
ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs,
ARRAY_SIZE(mt6397_devs), NULL,
0, NULL);
break;
default:
......@@ -296,14 +310,6 @@ static int mt6397_probe(struct platform_device *pdev)
break;
}
pmic->irq = platform_get_irq(pdev, 0);
if (pmic->irq > 0) {
ret = mt6397_irq_init(pmic);
if (ret)
return ret;
}
fail_irq:
if (ret) {
irq_domain_remove(pmic->irq_domain);
dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
......@@ -312,13 +318,6 @@ static int mt6397_probe(struct platform_device *pdev)
return ret;
}
static int mt6397_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
return 0;
}
static const struct of_device_id mt6397_of_match[] = {
{ .compatible = "mediatek,mt6397" },
{ .compatible = "mediatek,mt6323" },
......@@ -334,7 +333,6 @@ MODULE_DEVICE_TABLE(platform, mt6397_id);
static struct platform_driver mt6397_driver = {
.probe = mt6397_probe,
.remove = mt6397_remove,
.driver = {
.name = "mt6397",
.of_match_table = of_match_ptr(mt6397_of_match),
......
......@@ -269,6 +269,8 @@ static int usbtll_omap_probe(struct platform_device *pdev)
if (IS_ERR(tll->ch_clk[i]))
dev_dbg(dev, "can't get clock : %s\n", clkname);
else
clk_prepare(tll->ch_clk[i]);
}
pm_runtime_put_sync(dev);
......@@ -301,9 +303,12 @@ static int usbtll_omap_remove(struct platform_device *pdev)
tll_dev = NULL;
spin_unlock(&tll_lock);
for (i = 0; i < tll->nch; i++)
if (!IS_ERR(tll->ch_clk[i]))
for (i = 0; i < tll->nch; i++) {
if (!IS_ERR(tll->ch_clk[i])) {
clk_unprepare(tll->ch_clk[i]);
clk_put(tll->ch_clk[i]);
}
}
pm_runtime_disable(&pdev->dev);
return 0;
......@@ -420,7 +425,7 @@ int omap_tll_enable(struct usbhs_omap_platform_data *pdata)
if (IS_ERR(tll->ch_clk[i]))
continue;
r = clk_prepare_enable(tll->ch_clk[i]);
r = clk_enable(tll->ch_clk[i]);
if (r) {
dev_err(tll_dev,
"Error enabling ch %d clock: %d\n", i, r);
......@@ -448,7 +453,7 @@ int omap_tll_disable(struct usbhs_omap_platform_data *pdata)
for (i = 0; i < tll->nch; i++) {
if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
if (!IS_ERR(tll->ch_clk[i]))
clk_disable_unprepare(tll->ch_clk[i]);
clk_disable(tll->ch_clk[i]);
}
}
......
......@@ -389,17 +389,10 @@ int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
irq_clear_status_flags(__irq, IRQ_NOREQUEST);
}
ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
"rc5t583", rc5t583);
ret = devm_request_threaded_irq(rc5t583->dev, irq, NULL, rc5t583_irq,
IRQF_ONESHOT, "rc5t583", rc5t583);
if (ret < 0)
dev_err(rc5t583->dev,
"Error in registering interrupt error: %d\n", ret);
return ret;
}
int rc5t583_irq_exit(struct rc5t583 *rc5t583)
{
if (rc5t583->chip_irq)
free_irq(rc5t583->chip_irq, rc5t583);
return 0;
}
......@@ -252,7 +252,6 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c,
struct rc5t583 *rc5t583;
struct rc5t583_platform_data *pdata = dev_get_platdata(&i2c->dev);
int ret;
bool irq_init_success = false;
if (!pdata) {
dev_err(&i2c->dev, "Err: Platform data not found\n");
......@@ -284,31 +283,15 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c,
/* Still continue with warning, if irq init fails */
if (ret)
dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
else
irq_init_success = true;
}
ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
ret = devm_mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
ARRAY_SIZE(rc5t583_subdevs), NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
goto err_add_devs;
}
return 0;
err_add_devs:
if (irq_init_success)
rc5t583_irq_exit(rc5t583);
return ret;
}
static int rc5t583_i2c_remove(struct i2c_client *i2c)
{
struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
}
mfd_remove_devices(rc5t583->dev);
rc5t583_irq_exit(rc5t583);
return 0;
}
......@@ -324,7 +307,6 @@ static struct i2c_driver rc5t583_i2c_driver = {
.name = "rc5t583",
},
.probe = rc5t583_i2c_probe,
.remove = rc5t583_i2c_remove,
.id_table = rc5t583_i2c_id,
};
......
......@@ -85,16 +85,12 @@ static int rdc321x_sb_probe(struct pci_dev *pdev,
rdc321x_gpio_pdata.sb_pdev = pdev;
rdc321x_wdt_pdata.sb_pdev = pdev;
return mfd_add_devices(&pdev->dev, -1,
rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells),
return devm_mfd_add_devices(&pdev->dev, -1,
rdc321x_sb_cells,
ARRAY_SIZE(rdc321x_sb_cells),
NULL, 0, NULL);
}
static void rdc321x_sb_remove(struct pci_dev *pdev)
{
mfd_remove_devices(&pdev->dev);
}
static const struct pci_device_id rdc321x_sb_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) },
{}
......@@ -105,7 +101,6 @@ static struct pci_driver rdc321x_sb_driver = {
.name = "RDC321x Southbridge",
.id_table = rdc321x_sb_table,
.probe = rdc321x_sb_probe,
.remove = rdc321x_sb_remove,
};
module_pci_driver(rdc321x_sb_driver);
......
......@@ -213,9 +213,9 @@ static int rk808_probe(struct i2c_client *client,
rk808->i2c = client;
i2c_set_clientdata(client, rk808);
ret = mfd_add_devices(&client->dev, -1,
rk808s, ARRAY_SIZE(rk808s),
NULL, 0, regmap_irq_get_domain(rk808->irq_data));
ret = devm_mfd_add_devices(&client->dev, -1,
rk808s, ARRAY_SIZE(rk808s), NULL, 0,
regmap_irq_get_domain(rk808->irq_data));
if (ret) {
dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
goto err_irq;
......@@ -240,7 +240,6 @@ static int rk808_remove(struct i2c_client *client)
struct rk808 *rk808 = i2c_get_clientdata(client);
regmap_del_irq_chip(client->irq, rk808->irq_data);
mfd_remove_devices(&client->dev);
pm_power_off = NULL;
return 0;
......
......@@ -78,7 +78,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = mfd_add_devices(&i2c->dev, -1, rn5t618_cells,
ret = devm_mfd_add_devices(&i2c->dev, -1, rn5t618_cells,
ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
......@@ -102,7 +102,6 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c)
pm_power_off = NULL;
}
mfd_remove_devices(&i2c->dev);
return 0;
}
......
......@@ -97,7 +97,7 @@ static int rt5033_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = mfd_add_devices(rt5033->dev, -1, rt5033_devs,
ret = devm_mfd_add_devices(rt5033->dev, -1, rt5033_devs,
ARRAY_SIZE(rt5033_devs), NULL, 0,
regmap_irq_get_domain(rt5033->irq_data));
if (ret < 0) {
......@@ -110,13 +110,6 @@ static int rt5033_i2c_probe(struct i2c_client *i2c,
return 0;
}
static int rt5033_i2c_remove(struct i2c_client *i2c)
{
mfd_remove_devices(&i2c->dev);
return 0;
}
static const struct i2c_device_id rt5033_i2c_id[] = {
{ "rt5033", },
{ }
......@@ -135,7 +128,6 @@ static struct i2c_driver rt5033_driver = {
.of_match_table = of_match_ptr(rt5033_dt_match),
},
.probe = rt5033_i2c_probe,
.remove = rt5033_i2c_remove,
.id_table = rt5033_i2c_id,
};
module_i2c_driver(rt5033_driver);
......
......@@ -481,29 +481,16 @@ static int sec_pmic_probe(struct i2c_client *i2c,
/* If this happens the probe function is problem */
BUG();
}
ret = mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL,
0, NULL);
ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs,
NULL, 0, NULL);
if (ret)
goto err_mfd;
return ret;
device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
sec_pmic_configure(sec_pmic);
sec_pmic_dump_rev(sec_pmic);
return ret;
err_mfd:
sec_irq_exit(sec_pmic);
return ret;
}
static int sec_pmic_remove(struct i2c_client *i2c)
{
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
mfd_remove_devices(sec_pmic->dev);
sec_irq_exit(sec_pmic);
return 0;
}
static void sec_pmic_shutdown(struct i2c_client *i2c)
......@@ -583,7 +570,6 @@ static struct i2c_driver sec_pmic_driver = {
.of_match_table = of_match_ptr(sec_dt_match),
},
.probe = sec_pmic_probe,
.remove = sec_pmic_remove,
.shutdown = sec_pmic_shutdown,
.id_table = sec_pmic_id,
};
......
......@@ -483,7 +483,8 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
return -EINVAL;
}
ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq,
ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic,
sec_pmic->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
sec_pmic->irq_base, sec_irq_chip,
&sec_pmic->irq_data);
......@@ -500,8 +501,3 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
return 0;
}
void sec_irq_exit(struct sec_pmic_dev *sec_pmic)
{
regmap_del_irq_chip(sec_pmic->irq, sec_pmic->irq_data);
}
......@@ -64,19 +64,14 @@ static int sky81452_probe(struct i2c_client *client,
cells[1].platform_data = pdata->regulator_init_data;
cells[1].pdata_size = sizeof(*pdata->regulator_init_data);
ret = mfd_add_devices(dev, -1, cells, ARRAY_SIZE(cells), NULL, 0, NULL);
ret = devm_mfd_add_devices(dev, -1, cells, ARRAY_SIZE(cells),
NULL, 0, NULL);
if (ret)
dev_err(dev, "failed to add child devices. err=%d\n", ret);
return ret;
}
static int sky81452_remove(struct i2c_client *client)
{
mfd_remove_devices(&client->dev);
return 0;
}
static const struct i2c_device_id sky81452_ids[] = {
{ "sky81452" },
{ }
......@@ -97,7 +92,6 @@ static struct i2c_driver sky81452_driver = {
.of_match_table = of_match_ptr(sky81452_of_match),
},
.probe = sky81452_probe,
.remove = sky81452_remove,
.id_table = sky81452_ids,
};
......
......@@ -879,11 +879,6 @@ static int sm501_register_display(struct sm501_devdata *sm,
#ifdef CONFIG_MFD_SM501_GPIO
static inline struct sm501_gpio_chip *to_sm501_gpio(struct gpio_chip *gc)
{
return container_of(gc, struct sm501_gpio_chip, gpio);
}
static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio)
{
return container_of(gpio, struct sm501_devdata, gpio);
......@@ -892,7 +887,7 @@ static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio)
static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip);
struct sm501_gpio_chip *smgpio = gpiochip_get_data(chip);
unsigned long result;
result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
......@@ -923,7 +918,7 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
struct sm501_gpio_chip *smchip = gpiochip_get_data(chip);
struct sm501_gpio *smgpio = smchip->ourgpio;
unsigned long bit = 1 << offset;
void __iomem *regs = smchip->regbase;
......@@ -948,7 +943,7 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
{
struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
struct sm501_gpio_chip *smchip = gpiochip_get_data(chip);
struct sm501_gpio *smgpio = smchip->ourgpio;
void __iomem *regs = smchip->regbase;
unsigned long bit = 1 << offset;
......@@ -974,7 +969,7 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
static int sm501_gpio_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
struct sm501_gpio_chip *smchip = gpiochip_get_data(chip);
struct sm501_gpio *smgpio = smchip->ourgpio;
unsigned long bit = 1 << offset;
void __iomem *regs = smchip->regbase;
......@@ -1039,7 +1034,7 @@ static int sm501_gpio_register_chip(struct sm501_devdata *sm,
gchip->base = base;
chip->ourgpio = gpio;
return gpiochip_add(gchip);
return gpiochip_add_data(gchip, chip);
}
static int sm501_register_gpio(struct sm501_devdata *sm)
......
......@@ -80,15 +80,6 @@ static int smsc_i2c_probe(struct i2c_client *i2c,
return ret;
}
static int smsc_i2c_remove(struct i2c_client *i2c)
{
struct smsc *smsc = i2c_get_clientdata(i2c);
mfd_remove_devices(smsc->dev);
return 0;
}
static const struct i2c_device_id smsc_i2c_id[] = {
{ "smscece1099", 0},
{},
......@@ -100,7 +91,6 @@ static struct i2c_driver smsc_i2c_driver = {
.name = "smsc",
},
.probe = smsc_i2c_probe,
.remove = smsc_i2c_remove,
.id_table = smsc_i2c_id,
};
......
......@@ -206,7 +206,7 @@ static int stw481x_probe(struct i2c_client *client,
stw481x_cells[i].pdata_size = sizeof(*stw481x);
}
ret = mfd_add_devices(&client->dev, 0, stw481x_cells,
ret = devm_mfd_add_devices(&client->dev, 0, stw481x_cells,
ARRAY_SIZE(stw481x_cells), NULL, 0, NULL);
if (ret)
return ret;
......@@ -216,12 +216,6 @@ static int stw481x_probe(struct i2c_client *client,
return ret;
}
static int stw481x_remove(struct i2c_client *client)
{
mfd_remove_devices(&client->dev);
return 0;
}
/*
* This ID table is completely unused, as this is a pure
* device-tree probed driver, but it has to be here due to
......@@ -246,7 +240,6 @@ static struct i2c_driver stw481x_driver = {
.of_match_table = stw481x_match,
},
.probe = stw481x_probe,
.remove = stw481x_remove,
.id_table = stw481x_id,
};
......
......@@ -24,7 +24,7 @@
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/tc6393xb.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#define SCR_REVID 0x08 /* b Revision ID */
......@@ -434,7 +434,7 @@ static struct mfd_cell tc6393xb_cells[] = {
static int tc6393xb_gpio_get(struct gpio_chip *chip,
unsigned offset)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
/* XXX: does dsr also represent inputs? */
return !!(tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8))
......@@ -444,7 +444,7 @@ static int tc6393xb_gpio_get(struct gpio_chip *chip,
static void __tc6393xb_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
u8 dsr;
dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8));
......@@ -459,7 +459,7 @@ static void __tc6393xb_gpio_set(struct gpio_chip *chip,
static void tc6393xb_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&tc6393xb->lock, flags);
......@@ -472,7 +472,7 @@ static void tc6393xb_gpio_set(struct gpio_chip *chip,
static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
unsigned long flags;
u8 doecr;
......@@ -490,7 +490,7 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
unsigned long flags;
u8 doecr;
......@@ -517,7 +517,7 @@ static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base)
tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input;
tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output;
return gpiochip_add(&tc6393xb->gpio);
return gpiochip_add_data(&tc6393xb->gpio, tc6393xb);
}
/*--------------------------------------------------------------------------*/
......
......@@ -21,7 +21,6 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps6105x.h>
......
......@@ -34,7 +34,7 @@
#include <linux/i2c/tps65010.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
/*-------------------------------------------------------------------------*/
......@@ -477,7 +477,7 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
if (offset < 4) {
struct tps65010 *tps;
tps = container_of(chip, struct tps65010, chip);
tps = gpiochip_get_data(chip);
if (!(tps->outmask & (1 << offset)))
return -EINVAL;
tps65010_set_gpio_out_value(offset + 1, value);
......@@ -494,7 +494,7 @@ static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset)
int value;
struct tps65010 *tps;
tps = container_of(chip, struct tps65010, chip);
tps = gpiochip_get_data(chip);
if (offset < 4) {
value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
......@@ -651,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client,
tps->chip.ngpio = 7;
tps->chip.can_sleep = 1;
status = gpiochip_add(&tps->chip);
status = gpiochip_add_data(&tps->chip, tps);
if (status < 0)
dev_err(&client->dev, "can't add gpiochip, err %d\n",
status);
......
......@@ -100,18 +100,10 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c,
tps6507x->read_dev = tps6507x_i2c_read_device;
tps6507x->write_dev = tps6507x_i2c_write_device;
return mfd_add_devices(tps6507x->dev, -1, tps6507x_devs,
return devm_mfd_add_devices(tps6507x->dev, -1, tps6507x_devs,
ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL);
}
static int tps6507x_i2c_remove(struct i2c_client *i2c)
{
struct tps6507x_dev *tps6507x = i2c_get_clientdata(i2c);
mfd_remove_devices(tps6507x->dev);
return 0;
}
static const struct i2c_device_id tps6507x_i2c_id[] = {
{ "tps6507x", 0 },
{ }
......@@ -132,7 +124,6 @@ static struct i2c_driver tps6507x_i2c_driver = {
.of_match_table = of_match_ptr(tps6507x_of_match),
},
.probe = tps6507x_i2c_probe,
.remove = tps6507x_i2c_remove,
.id_table = tps6507x_i2c_id,
};
......
......@@ -205,7 +205,7 @@ static int tps65217_probe(struct i2c_client *client,
return ret;
}
ret = mfd_add_devices(tps->dev, -1, tps65217s,
ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
ARRAY_SIZE(tps65217s), NULL, 0, NULL);
if (ret < 0) {
dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
......@@ -235,15 +235,6 @@ static int tps65217_probe(struct i2c_client *client,
return 0;
}
static int tps65217_remove(struct i2c_client *client)
{
struct tps65217 *tps = i2c_get_clientdata(client);
mfd_remove_devices(tps->dev);
return 0;
}
static const struct i2c_device_id tps65217_id_table[] = {
{"tps65217", TPS65217},
{ /* sentinel */ }
......@@ -257,7 +248,6 @@ static struct i2c_driver tps65217_driver = {
},
.id_table = tps65217_id_table,
.probe = tps65217_probe,
.remove = tps65217_remove,
};
static int __init tps65217_init(void)
......
......@@ -252,7 +252,8 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq,
}
tps65910->chip_irq = irq;
ret = regmap_add_irq_chip(tps65910->regmap, tps65910->chip_irq,
ret = devm_regmap_add_irq_chip(tps65910->dev, tps65910->regmap,
tps65910->chip_irq,
IRQF_ONESHOT, pdata->irq_base,
tps6591x_irqs_chip, &tps65910->irq_data);
if (ret < 0) {
......@@ -262,13 +263,6 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq,
return ret;
}
static int tps65910_irq_exit(struct tps65910 *tps65910)
{
if (tps65910->chip_irq > 0)
regmap_del_irq_chip(tps65910->chip_irq, tps65910->irq_data);
return 0;
}
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
struct tps65910 *tps65910 = dev_get_drvdata(dev);
......@@ -510,29 +504,18 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
pm_power_off = tps65910_power_off;
}
ret = mfd_add_devices(tps65910->dev, -1,
ret = devm_mfd_add_devices(tps65910->dev, -1,
tps65910s, ARRAY_SIZE(tps65910s),
NULL, 0,
regmap_irq_get_domain(tps65910->irq_data));
if (ret < 0) {
dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret);
tps65910_irq_exit(tps65910);
return ret;
}
return ret;
}
static int tps65910_i2c_remove(struct i2c_client *i2c)
{
struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
tps65910_irq_exit(tps65910);
mfd_remove_devices(tps65910->dev);
return 0;
}
static const struct i2c_device_id tps65910_i2c_id[] = {
{ "tps65910", TPS65910 },
{ "tps65911", TPS65911 },
......@@ -547,7 +530,6 @@ static struct i2c_driver tps65910_i2c_driver = {
.of_match_table = of_match_ptr(tps65910_of_match),
},
.probe = tps65910_i2c_probe,
.remove = tps65910_i2c_remove,
.id_table = tps65910_i2c_id,
};
......
/*
* linux/drivers/i2c/chips/twl4030-power.c
*
* Handle TWL4030 Power initialization
*
......
......@@ -291,7 +291,11 @@ int twl6040_power(struct twl6040 *twl6040, int on)
if (twl6040->power_count++)
goto out;
clk_prepare_enable(twl6040->clk32k);
ret = clk_prepare_enable(twl6040->clk32k);
if (ret) {
twl6040->power_count = 0;
goto out;
}
/* Allow writes to the chip */
regcache_cache_only(twl6040->regmap, false);
......@@ -300,6 +304,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* use automatic power-up sequence */
ret = twl6040_power_up_automatic(twl6040);
if (ret) {
clk_disable_unprepare(twl6040->clk32k);
twl6040->power_count = 0;
goto out;
}
......@@ -307,6 +312,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* use manual power-up sequence */
ret = twl6040_power_up_manual(twl6040);
if (ret) {
clk_disable_unprepare(twl6040->clk32k);
twl6040->power_count = 0;
goto out;
}
......
......@@ -28,7 +28,7 @@
#include <linux/mutex.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
static DEFINE_MUTEX(ucb1x00_mutex);
static LIST_HEAD(ucb1x00_drivers);
......@@ -109,7 +109,7 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
struct ucb1x00 *ucb = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&ucb->io_lock, flags);
......@@ -126,7 +126,7 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
struct ucb1x00 *ucb = gpiochip_get_data(chip);
unsigned val;
ucb1x00_enable(ucb);
......@@ -138,7 +138,7 @@ static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
struct ucb1x00 *ucb = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&ucb->io_lock, flags);
......@@ -154,7 +154,7 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
, int value)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
struct ucb1x00 *ucb = gpiochip_get_data(chip);
unsigned long flags;
unsigned old, mask = 1 << offset;
......@@ -181,7 +181,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
struct ucb1x00 *ucb = gpiochip_get_data(chip);
return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO;
}
......@@ -579,7 +579,7 @@ static int ucb1x00_probe(struct mcp *mcp)
ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
ucb->gpio.to_irq = ucb1x00_to_irq;
ret = gpiochip_add(&ucb->gpio);
ret = gpiochip_add_data(&ucb->gpio, ucb);
if (ret)
goto err_gpio_add;
} else
......
......@@ -202,7 +202,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
NULL, NULL, NULL, NULL, 0);
mmc_gpio_chip->ngpio = 2;
gpiochip_add(mmc_gpio_chip);
gpiochip_add_data(mmc_gpio_chip, NULL);
return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
vexpress_sysreg_cells,
......
......@@ -170,15 +170,6 @@ static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
return 0;
}
static int wl1273_core_remove(struct i2c_client *client)
{
dev_dbg(&client->dev, "%s\n", __func__);
mfd_remove_devices(&client->dev);
return 0;
}
static int wl1273_core_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -237,7 +228,7 @@ static int wl1273_core_probe(struct i2c_client *client,
dev_dbg(&client->dev, "%s: number of children: %d.\n",
__func__, children);
r = mfd_add_devices(&client->dev, -1, core->cells,
r = devm_mfd_add_devices(&client->dev, -1, core->cells,
children, NULL, 0, NULL);
if (r)
goto err;
......@@ -258,7 +249,6 @@ static struct i2c_driver wl1273_core_driver = {
},
.probe = wl1273_core_probe,
.id_table = wl1273_driver_id_table,
.remove = wl1273_core_remove,
};
static int __init wl1273_core_init(void)
......
......@@ -3066,6 +3066,7 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_AOD_IRQ_RAW_STATUS:
case ARIZONA_FX_CTRL2:
case ARIZONA_ASRC_STATUS:
case ARIZONA_CLOCK_CONTROL:
case ARIZONA_DSP_STATUS:
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
......
......@@ -35,27 +35,6 @@ static bool wm8400_volatile(struct device *dev, unsigned int reg)
}
}
/**
* wm8400_reg_read - Single register read
*
* @wm8400: Pointer to wm8400 control structure
* @reg: Register to read
*
* @return Read value
*/
u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg)
{
unsigned int val;
int ret;
ret = regmap_read(wm8400->regmap, reg, &val);
if (ret < 0)
return ret;
return val;
}
EXPORT_SYMBOL_GPL(wm8400_reg_read);
int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data)
{
return regmap_bulk_read(wm8400->regmap, reg, data, count);
......@@ -70,7 +49,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
.pdata_size = sizeof(*wm8400),
};
return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL);
return devm_mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL);
}
/*
......@@ -111,7 +90,7 @@ static int wm8400_init(struct wm8400 *wm8400,
ret = wm8400_register_codec(wm8400);
if (ret != 0) {
dev_err(wm8400->dev, "Failed to register codec\n");
goto err_children;
return ret;
}
if (pdata && pdata->platform_init) {
......@@ -119,21 +98,12 @@ static int wm8400_init(struct wm8400 *wm8400,
if (ret != 0) {
dev_err(wm8400->dev, "Platform init failed: %d\n",
ret);
goto err_children;
return ret;
}
} else
dev_warn(wm8400->dev, "No platform initialisation supplied\n");
return 0;
err_children:
mfd_remove_devices(wm8400->dev);
return ret;
}
static void wm8400_release(struct wm8400 *wm8400)
{
mfd_remove_devices(wm8400->dev);
}
static const struct regmap_config wm8400_regmap_config = {
......@@ -156,7 +126,7 @@ void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
}
EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
#if IS_ENABLED(CONFIG_I2C)
static int wm8400_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
......@@ -176,15 +146,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
return wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
}
static int wm8400_i2c_remove(struct i2c_client *i2c)
{
struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
wm8400_release(wm8400);
return 0;
}
static const struct i2c_device_id wm8400_i2c_id[] = {
{ "wm8400", 0 },
{ }
......@@ -196,7 +157,6 @@ static struct i2c_driver wm8400_i2c_driver = {
.name = "WM8400",
},
.probe = wm8400_i2c_probe,
.remove = wm8400_i2c_remove,
.id_table = wm8400_i2c_id,
};
#endif
......@@ -205,7 +165,7 @@ static int __init wm8400_module_init(void)
{
int ret = -ENODEV;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8400_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %d\n", ret);
......@@ -217,7 +177,7 @@ subsys_initcall(wm8400_module_init);
static void __exit wm8400_module_exit(void)
{
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8400_i2c_driver);
#endif
}
......
......@@ -110,4 +110,9 @@
#define ARIZONA_ACCDET_MODE_HPM 4
#define ARIZONA_ACCDET_MODE_ADC 7
#define ARIZONA_GPSW_OPEN 0
#define ARIZONA_GPSW_CLOSED 1
#define ARIZONA_GPSW_CLAMP_ENABLED 2
#define ARIZONA_GPSW_CLAMP_DISABLED 3
#endif
/*
* This header provides macros for MAXIM MAX77620 device bindings.
*
* Copyright (c) 2016, NVIDIA Corporation.
* Author: Laxman Dewangan <ldewangan@nvidia.com>
*/
#ifndef _DT_BINDINGS_MFD_MAX77620_H
#define _DT_BINDINGS_MFD_MAX77620_H
/* MAX77620 interrupts */
#define MAX77620_IRQ_TOP_GLBL 0 /* Low-Battery */
#define MAX77620_IRQ_TOP_SD 1 /* SD power fail */
#define MAX77620_IRQ_TOP_LDO 2 /* LDO power fail */
#define MAX77620_IRQ_TOP_GPIO 3 /* GPIO internal int to MAX77620 */
#define MAX77620_IRQ_TOP_RTC 4 /* RTC */
#define MAX77620_IRQ_TOP_32K 5 /* 32kHz oscillator */
#define MAX77620_IRQ_TOP_ONOFF 6 /* ON/OFF oscillator */
#define MAX77620_IRQ_LBT_MBATLOW 7 /* Thermal alarm status, > 120C */
#define MAX77620_IRQ_LBT_TJALRM1 8 /* Thermal alarm status, > 120C */
#define MAX77620_IRQ_LBT_TJALRM2 9 /* Thermal alarm status, > 140C */
/* FPS event source */
#define MAX77620_FPS_EVENT_SRC_EN0 0
#define MAX77620_FPS_EVENT_SRC_EN1 1
#define MAX77620_FPS_EVENT_SRC_SW 2
/* Device state when FPS event LOW */
#define MAX77620_FPS_INACTIVE_STATE_SLEEP 0
#define MAX77620_FPS_INACTIVE_STATE_LOW_POWER 1
/* FPS source */
#define MAX77620_FPS_SRC_0 0
#define MAX77620_FPS_SRC_1 1
#define MAX77620_FPS_SRC_2 2
#define MAX77620_FPS_SRC_NONE 3
#define MAX77620_FPS_SRC_DEF 4
#endif
......@@ -20,6 +20,7 @@ enum {
AXP221_ID,
AXP223_ID,
AXP288_ID,
AXP809_ID,
NR_AXP20X_VARIANTS,
};
......@@ -264,6 +265,29 @@ enum {
AXP22X_REG_ID_MAX,
};
enum {
AXP809_DCDC1 = 0,
AXP809_DCDC2,
AXP809_DCDC3,
AXP809_DCDC4,
AXP809_DCDC5,
AXP809_DC1SW,
AXP809_DC5LDO,
AXP809_ALDO1,
AXP809_ALDO2,
AXP809_ALDO3,
AXP809_ELDO1,
AXP809_ELDO2,
AXP809_ELDO3,
AXP809_DLDO1,
AXP809_DLDO2,
AXP809_RTC_LDO,
AXP809_LDO_IO0,
AXP809_LDO_IO1,
AXP809_SW,
AXP809_REG_ID_MAX,
};
/* IRQs */
enum {
AXP152_IRQ_LDO0IN_CONNECT = 1,
......@@ -390,6 +414,41 @@ enum axp288_irqs {
AXP288_IRQ_BC_USB_CHNG,
};
enum axp809_irqs {
AXP809_IRQ_ACIN_OVER_V = 1,
AXP809_IRQ_ACIN_PLUGIN,
AXP809_IRQ_ACIN_REMOVAL,
AXP809_IRQ_VBUS_OVER_V,
AXP809_IRQ_VBUS_PLUGIN,
AXP809_IRQ_VBUS_REMOVAL,
AXP809_IRQ_VBUS_V_LOW,
AXP809_IRQ_BATT_PLUGIN,
AXP809_IRQ_BATT_REMOVAL,
AXP809_IRQ_BATT_ENT_ACT_MODE,
AXP809_IRQ_BATT_EXIT_ACT_MODE,
AXP809_IRQ_CHARG,
AXP809_IRQ_CHARG_DONE,
AXP809_IRQ_BATT_CHG_TEMP_HIGH,
AXP809_IRQ_BATT_CHG_TEMP_HIGH_END,
AXP809_IRQ_BATT_CHG_TEMP_LOW,
AXP809_IRQ_BATT_CHG_TEMP_LOW_END,
AXP809_IRQ_BATT_ACT_TEMP_HIGH,
AXP809_IRQ_BATT_ACT_TEMP_HIGH_END,
AXP809_IRQ_BATT_ACT_TEMP_LOW,
AXP809_IRQ_BATT_ACT_TEMP_LOW_END,
AXP809_IRQ_DIE_TEMP_HIGH,
AXP809_IRQ_LOW_PWR_LVL1,
AXP809_IRQ_LOW_PWR_LVL2,
AXP809_IRQ_TIMER,
AXP809_IRQ_PEK_RIS_EDGE,
AXP809_IRQ_PEK_FAL_EDGE,
AXP809_IRQ_PEK_SHORT,
AXP809_IRQ_PEK_LONG,
AXP809_IRQ_PEK_OVER_OFF,
AXP809_IRQ_GPIO1_INPUT,
AXP809_IRQ_GPIO0_INPUT,
};
#define AXP288_TS_ADC_H 0x58
#define AXP288_TS_ADC_L 0x59
#define AXP288_GP_ADC_H 0x5a
......
......@@ -131,4 +131,8 @@ static inline int mfd_add_hotplug_devices(struct device *parent,
extern void mfd_remove_devices(struct device *parent);
extern int devm_mfd_add_devices(struct device *dev, int id,
const struct mfd_cell *cells, int n_devs,
struct resource *mem_base,
int irq_base, struct irq_domain *irq_domain);
#endif
/*
* Device driver for regulators in hi655x IC
*
* Copyright (c) 2016 Hisilicon.
*
* Authors:
* Chen Feng <puck.chen@hisilicon.com>
* Fei Wang <w.f@huawei.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.
*/
#ifndef __HI655X_PMIC_H
#define __HI655X_PMIC_H
/* Hi655x registers are mapped to memory bus in 4 bytes stride */
#define HI655X_STRIDE 4
#define HI655X_BUS_ADDR(x) ((x) << 2)
#define HI655X_BITS 8
#define HI655X_NR_IRQ 32
#define HI655X_IRQ_STAT_BASE (0x003 << 2)
#define HI655X_IRQ_MASK_BASE (0x007 << 2)
#define HI655X_ANA_IRQM_BASE (0x1b5 << 2)
#define HI655X_IRQ_ARRAY 4
#define HI655X_IRQ_MASK 0xFF
#define HI655X_IRQ_CLR 0xFF
#define HI655X_VER_REG 0x00
#define PMU_VER_START 0x10
#define PMU_VER_END 0x38
#define RESERVE_INT BIT(7)
#define PWRON_D20R_INT BIT(6)
#define PWRON_D20F_INT BIT(5)
#define PWRON_D4SR_INT BIT(4)
#define VSYS_6P0_D200UR_INT BIT(3)
#define VSYS_UV_D3R_INT BIT(2)
#define VSYS_2P5_R_INT BIT(1)
#define OTMP_D1R_INT BIT(0)
struct hi655x_pmic {
struct resource *res;
struct device *dev;
struct regmap *regmap;
int gpio;
unsigned int ver;
struct regmap_irq_chip_data *irq_data;
};
#endif
/*
* Defining registers address and its bit definitions of MAX77620 and MAX20024
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#ifndef _MFD_MAX77620_H_
#define _MFD_MAX77620_H_
#include <linux/types.h>
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
#define MAX77620_REG_CNFGGLBL1 0x00
#define MAX77620_REG_CNFGGLBL2 0x01
#define MAX77620_REG_CNFGGLBL3 0x02
#define MAX77620_REG_CNFG1_32K 0x03
#define MAX77620_REG_CNFGBBC 0x04
#define MAX77620_REG_IRQTOP 0x05
#define MAX77620_REG_INTLBT 0x06
#define MAX77620_REG_IRQSD 0x07
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
#define MAX77620_REG_IRQ_LVL2_L8 0x09
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
#define MAX77620_REG_ONOFFIRQ 0x0B
#define MAX77620_REG_NVERC 0x0C
#define MAX77620_REG_IRQTOPM 0x0D
#define MAX77620_REG_INTENLBT 0x0E
#define MAX77620_REG_IRQMASKSD 0x0F
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
#define MAX77620_REG_IRQ_MSK_L8 0x11
#define MAX77620_REG_ONOFFIRQM 0x12
#define MAX77620_REG_STATLBT 0x13
#define MAX77620_REG_STATSD 0x14
#define MAX77620_REG_ONOFFSTAT 0x15
/* SD and LDO Registers */
#define MAX77620_REG_SD0 0x16
#define MAX77620_REG_SD1 0x17
#define MAX77620_REG_SD2 0x18
#define MAX77620_REG_SD3 0x19
#define MAX77620_REG_SD4 0x1A
#define MAX77620_REG_DVSSD0 0x1B
#define MAX77620_REG_DVSSD1 0x1C
#define MAX77620_REG_SD0_CFG 0x1D
#define MAX77620_REG_SD1_CFG 0x1E
#define MAX77620_REG_SD2_CFG 0x1F
#define MAX77620_REG_SD3_CFG 0x20
#define MAX77620_REG_SD4_CFG 0x21
#define MAX77620_REG_SD_CFG2 0x22
#define MAX77620_REG_LDO0_CFG 0x23
#define MAX77620_REG_LDO0_CFG2 0x24
#define MAX77620_REG_LDO1_CFG 0x25
#define MAX77620_REG_LDO1_CFG2 0x26
#define MAX77620_REG_LDO2_CFG 0x27
#define MAX77620_REG_LDO2_CFG2 0x28
#define MAX77620_REG_LDO3_CFG 0x29
#define MAX77620_REG_LDO3_CFG2 0x2A
#define MAX77620_REG_LDO4_CFG 0x2B
#define MAX77620_REG_LDO4_CFG2 0x2C
#define MAX77620_REG_LDO5_CFG 0x2D
#define MAX77620_REG_LDO5_CFG2 0x2E
#define MAX77620_REG_LDO6_CFG 0x2F
#define MAX77620_REG_LDO6_CFG2 0x30
#define MAX77620_REG_LDO7_CFG 0x31
#define MAX77620_REG_LDO7_CFG2 0x32
#define MAX77620_REG_LDO8_CFG 0x33
#define MAX77620_REG_LDO8_CFG2 0x34
#define MAX77620_REG_LDO_CFG3 0x35
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
/* LDO Configuration 3 */
#define MAX77620_TRACK4_MASK BIT(5)
#define MAX77620_TRACK4_SHIFT 5
/* Voltage */
#define MAX77620_SDX_VOLT_MASK 0xFF
#define MAX77620_SD0_VOLT_MASK 0x3F
#define MAX77620_SD1_VOLT_MASK 0x7F
#define MAX77620_LDO_VOLT_MASK 0x3F
#define MAX77620_REG_GPIO0 0x36
#define MAX77620_REG_GPIO1 0x37
#define MAX77620_REG_GPIO2 0x38
#define MAX77620_REG_GPIO3 0x39
#define MAX77620_REG_GPIO4 0x3A
#define MAX77620_REG_GPIO5 0x3B
#define MAX77620_REG_GPIO6 0x3C
#define MAX77620_REG_GPIO7 0x3D
#define MAX77620_REG_PUE_GPIO 0x3E
#define MAX77620_REG_PDE_GPIO 0x3F
#define MAX77620_REG_AME_GPIO 0x40
#define MAX77620_REG_ONOFFCNFG1 0x41
#define MAX77620_REG_ONOFFCNFG2 0x42
/* FPS Registers */
#define MAX77620_REG_FPS_CFG0 0x43
#define MAX77620_REG_FPS_CFG1 0x44
#define MAX77620_REG_FPS_CFG2 0x45
#define MAX77620_REG_FPS_LDO0 0x46
#define MAX77620_REG_FPS_LDO1 0x47
#define MAX77620_REG_FPS_LDO2 0x48
#define MAX77620_REG_FPS_LDO3 0x49
#define MAX77620_REG_FPS_LDO4 0x4A
#define MAX77620_REG_FPS_LDO5 0x4B
#define MAX77620_REG_FPS_LDO6 0x4C
#define MAX77620_REG_FPS_LDO7 0x4D
#define MAX77620_REG_FPS_LDO8 0x4E
#define MAX77620_REG_FPS_SD0 0x4F
#define MAX77620_REG_FPS_SD1 0x50
#define MAX77620_REG_FPS_SD2 0x51
#define MAX77620_REG_FPS_SD3 0x52
#define MAX77620_REG_FPS_SD4 0x53
#define MAX77620_REG_FPS_NONE 0
#define MAX77620_FPS_SRC_MASK 0xC0
#define MAX77620_FPS_SRC_SHIFT 6
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
#define MAX77620_FPS_EN_SRC_MASK 0x06
#define MAX77620_FPS_EN_SRC_SHIFT 1
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
#define MAX77620_FPS_ENFPS_SW 0x01
/* Minimum and maximum FPS period time (in microseconds) are
* different for MAX77620 and Max20024.
*/
#define MAX77620_FPS_PERIOD_MIN_US 40
#define MAX20024_FPS_PERIOD_MIN_US 20
#define MAX77620_FPS_PERIOD_MAX_US 2560
#define MAX20024_FPS_PERIOD_MAX_US 5120
#define MAX77620_REG_FPS_GPIO1 0x54
#define MAX77620_REG_FPS_GPIO2 0x55
#define MAX77620_REG_FPS_GPIO3 0x56
#define MAX77620_REG_FPS_RSO 0x57
#define MAX77620_REG_CID0 0x58
#define MAX77620_REG_CID1 0x59
#define MAX77620_REG_CID2 0x5A
#define MAX77620_REG_CID3 0x5B
#define MAX77620_REG_CID4 0x5C
#define MAX77620_REG_CID5 0x5D
#define MAX77620_REG_DVSSD4 0x5E
#define MAX20024_REG_MAX_ADD 0x70
#define MAX77620_CID_DIDM_MASK 0xF0
#define MAX77620_CID_DIDM_SHIFT 4
/* CNCG2SD */
#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1)
#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2)
/* Device Identification Metal */
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
/* Device Indentification OTP */
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
/* SD CNFG1 */
#define MAX77620_SD_SR_MASK 0xC0
#define MAX77620_SD_SR_SHIFT 6
#define MAX77620_SD_POWER_MODE_MASK 0x30
#define MAX77620_SD_POWER_MODE_SHIFT 4
#define MAX77620_SD_CFG1_ADE_MASK BIT(3)
#define MAX77620_SD_CFG1_ADE_DISABLE 0
#define MAX77620_SD_CFG1_ADE_ENABLE BIT(3)
#define MAX77620_SD_FPWM_MASK 0x04
#define MAX77620_SD_FPWM_SHIFT 2
#define MAX77620_SD_FSRADE_MASK 0x01
#define MAX77620_SD_FSRADE_SHIFT 0
#define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2)
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2)
#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0)
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0)
/* LDO_CNFG2 */
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
#define MAX77620_LDO_POWER_MODE_SHIFT 6
#define MAX77620_LDO_CFG2_ADE_MASK BIT(1)
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
#define MAX77620_LDO_CFG2_ADE_ENABLE BIT(1)
#define MAX77620_LDO_CFG2_SS_MASK BIT(0)
#define MAX77620_LDO_CFG2_SS_FAST BIT(0)
#define MAX77620_LDO_CFG2_SS_SLOW 0
#define MAX77620_IRQ_TOP_GLBL_MASK BIT(7)
#define MAX77620_IRQ_TOP_SD_MASK BIT(6)
#define MAX77620_IRQ_TOP_LDO_MASK BIT(5)
#define MAX77620_IRQ_TOP_GPIO_MASK BIT(4)
#define MAX77620_IRQ_TOP_RTC_MASK BIT(3)
#define MAX77620_IRQ_TOP_32K_MASK BIT(2)
#define MAX77620_IRQ_TOP_ONOFF_MASK BIT(1)
#define MAX77620_IRQ_LBM_MASK BIT(3)
#define MAX77620_IRQ_TJALRM1_MASK BIT(2)
#define MAX77620_IRQ_TJALRM2_MASK BIT(1)
#define MAX77620_PWR_I2C_ADDR 0x3c
#define MAX77620_RTC_I2C_ADDR 0x68
#define MAX77620_CNFG_GPIO_DRV_MASK BIT(0)
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL BIT(0)
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
#define MAX77620_CNFG_GPIO_DIR_MASK BIT(1)
#define MAX77620_CNFG_GPIO_DIR_INPUT BIT(1)
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK BIT(2)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK BIT(3)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH BIT(3)
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
#define MAX77620_CNFG_GPIO_INT_FALLING BIT(4)
#define MAX77620_CNFG_GPIO_INT_RISING BIT(5)
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 BIT(0)
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 BIT(1)
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 BIT(2)
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 BIT(3)
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 BIT(4)
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 BIT(5)
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 BIT(6)
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 BIT(7)
#define MAX77620_CNFG1_32K_OUT0_EN BIT(2)
#define MAX77620_ONOFFCNFG1_SFT_RST BIT(7)
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
#define MAX77620_ONOFFCNFG1_SLPEN BIT(2)
#define MAX77620_ONOFFCNFG1_PWR_OFF BIT(1)
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
#define MAX77620_ONOFFCNFG2_SFT_RST_WK BIT(7)
#define MAX77620_ONOFFCNFG2_WD_RST_WK BIT(6)
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK BIT(5)
#define MAX77620_ONOFFCNFG2_WK_ALARM1 BIT(2)
#define MAX77620_ONOFFCNFG2_WK_EN0 BIT(0)
#define MAX77620_GLBLM_MASK BIT(0)
#define MAX77620_WDTC_MASK 0x3
#define MAX77620_WDTOFFC BIT(4)
#define MAX77620_WDTSLPC BIT(3)
#define MAX77620_WDTEN BIT(2)
#define MAX77620_TWD_MASK 0x3
#define MAX77620_TWD_2s 0x0
#define MAX77620_TWD_16s 0x1
#define MAX77620_TWD_64s 0x2
#define MAX77620_TWD_128s 0x3
#define MAX77620_CNFGGLBL1_LBDAC_EN BIT(7)
#define MAX77620_CNFGGLBL1_MPPLD BIT(6)
#define MAX77620_CNFGGLBL1_LBHYST (BIT(5) | BIT(4))
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
#define MAX77620_CNFGGLBL1_LBRSTEN BIT(0)
/* CNFG BBC registers */
#define MAX77620_CNFGBBC_ENABLE BIT(0)
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE BIT(5)
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
#define MAX77620_FPS_COUNT 3
/* Interrupts */
enum {
MAX77620_IRQ_TOP_GLBL, /* Low-Battery */
MAX77620_IRQ_TOP_SD, /* SD power fail */
MAX77620_IRQ_TOP_LDO, /* LDO power fail */
MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */
MAX77620_IRQ_TOP_RTC, /* RTC */
MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */
MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */
MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */
MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */
MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */
};
/* GPIOs */
enum {
MAX77620_GPIO0,
MAX77620_GPIO1,
MAX77620_GPIO2,
MAX77620_GPIO3,
MAX77620_GPIO4,
MAX77620_GPIO5,
MAX77620_GPIO6,
MAX77620_GPIO7,
MAX77620_GPIO_NR,
};
/* FPS Source */
enum max77620_fps_src {
MAX77620_FPS_SRC_0,
MAX77620_FPS_SRC_1,
MAX77620_FPS_SRC_2,
MAX77620_FPS_SRC_NONE,
MAX77620_FPS_SRC_DEF,
};
enum max77620_chip_id {
MAX77620,
MAX20024,
};
struct max77620_chip {
struct device *dev;
struct regmap *rmap;
int chip_irq;
int irq_base;
/* chip id */
enum max77620_chip_id chip_id;
bool sleep_enable;
bool enable_global_lpm;
int shutdown_fps_period[MAX77620_FPS_COUNT];
int suspend_fps_period[MAX77620_FPS_COUNT];
struct regmap_irq_chip_data *top_irq_data;
struct regmap_irq_chip_data *gpio_irq_data;
};
#endif /* _MFD_MAX77620_H_ */
......@@ -16,6 +16,7 @@
#define __LINUX_MFD_SYSCON_H__
#include <linux/err.h>
#include <linux/errno.h>
struct device_node;
......
......@@ -923,7 +923,6 @@ struct wm8400 {
#define WM8400_LINE_CMP_VTHD_SHIFT 0 /* LINE_CMP_VTHD - [3:0] */
#define WM8400_LINE_CMP_VTHD_WIDTH 4 /* LINE_CMP_VTHD - [3:0] */
u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg);
int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data);
static inline int wm8400_set_bits(struct wm8400 *wm8400, u8 reg,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册