aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2017-05-29 19:54:21 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2017-05-29 19:54:21 -0700
commitd8f797c60661a90ee26ca9330cf85ede9aa2ec17 (patch)
tree5038609885fc3e4cb7f329d974875ac4411c6af5 /drivers/mfd
parentInput: tsc2007 - move header file out of I2C realm (diff)
parentLinux 4.12-rc3 (diff)
downloadlinux-dev-d8f797c60661a90ee26ca9330cf85ede9aa2ec17.tar.xz
linux-dev-d8f797c60661a90ee26ca9330cf85ede9aa2ec17.zip
Merge tag 'v4.12-rc3' into next
Sync with mainline to bring in changes in platform drovers dropping calls to sparse_keymap_free() so that we can remove it for good.
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig53
-rw-r--r--drivers/mfd/Makefile10
-rw-r--r--drivers/mfd/altera-a10sr.c4
-rw-r--r--drivers/mfd/arizona-core.c44
-rw-r--r--drivers/mfd/asic3.c56
-rw-r--r--drivers/mfd/atmel-smc.c314
-rw-r--r--drivers/mfd/axp20x-rsb.c1
-rw-r--r--drivers/mfd/axp20x.c129
-rw-r--r--drivers/mfd/cros_ec.c15
-rw-r--r--drivers/mfd/cros_ec_acpi_gpe.c103
-rw-r--r--drivers/mfd/cros_ec_spi.c9
-rw-r--r--drivers/mfd/da9062-core.c427
-rw-r--r--drivers/mfd/db8500-prcmu.c2
-rw-r--r--drivers/mfd/exynos-lpass.c50
-rw-r--r--drivers/mfd/hi655x-pmic.c3
-rw-r--r--drivers/mfd/intel-lpss-acpi.c4
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c25
-rw-r--r--drivers/mfd/intel_soc_pmic_core.c27
-rw-r--r--drivers/mfd/ipaq-micro.c3
-rw-r--r--drivers/mfd/lpc_ich.c12
-rw-r--r--drivers/mfd/menelaus.c4
-rw-r--r--drivers/mfd/motorola-cpcap.c34
-rw-r--r--drivers/mfd/mt6397-core.c3
-rw-r--r--drivers/mfd/mxs-lradc.c267
-rw-r--r--drivers/mfd/omap-usb-tll.c7
-rw-r--r--drivers/mfd/palmas.c16
-rw-r--r--drivers/mfd/rtsx_pcr.c2
-rw-r--r--drivers/mfd/sta2x11-mfd.c4
-rw-r--r--drivers/mfd/stm32-timers.c10
-rw-r--r--drivers/mfd/stmpe.c2
-rw-r--r--drivers/mfd/t7l66xb.c20
-rw-r--r--drivers/mfd/tc6393xb.c52
-rw-r--r--drivers/mfd/ti-lmu.c259
-rw-r--r--drivers/mfd/tps65912-spi.c4
-rw-r--r--drivers/mfd/twl4030-power.c8
-rw-r--r--drivers/mfd/wm831x-core.c29
-rw-r--r--drivers/mfd/wm831x-i2c.c19
-rw-r--r--drivers/mfd/wm831x-irq.c6
-rw-r--r--drivers/mfd/wm831x-spi.c18
39 files changed, 1826 insertions, 229 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 55ecdfb74d31..3eb5c93595f6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -121,6 +121,10 @@ config MFD_ATMEL_HLCDC
additional drivers must be enabled in order to use the
functionality of the device.
+config MFD_ATMEL_SMC
+ bool
+ select MFD_SYSCON
+
config MFD_BCM590XX
tristate "Broadcom BCM590xx PMUs"
select MFD_CORE
@@ -263,13 +267,14 @@ config MFD_DA9055
called "da9055"
config MFD_DA9062
- tristate "Dialog Semiconductor DA9062 PMIC Support"
+ tristate "Dialog Semiconductor DA9062/61 PMIC Support"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C
help
- Say yes here for support for the Dialog Semiconductor DA9062 PMIC.
+ Say yes here for support for the Dialog Semiconductor DA9061 and
+ DA9062 PMICs.
This includes the I2C driver and core APIs.
Additional drivers must be enabled in order to use the functionality
of the device.
@@ -344,6 +349,23 @@ config MFD_MC13XXX_I2C
help
Select this if your MC13xxx is connected via an I2C bus.
+config MFD_MXS_LRADC
+ tristate "Freescale i.MX23/i.MX28 LRADC"
+ depends on ARCH_MXS || COMPILE_TEST
+ select MFD_CORE
+ select STMP_DEVICE
+ help
+ Say yes here to build support for the Low Resolution
+ Analog-to-Digital Converter (LRADC) found on the i.MX23 and i.MX28
+ processors. This driver provides common support for accessing the
+ device, additional drivers must be enabled in order to use the
+ functionality of the device:
+ mxs-lradc-adc for ADC readings
+ mxs-lradc-ts for touchscreen support
+
+ This driver can also be built as a module. If so, the module will be
+ called mxs-lradc.
+
config MFD_MX25_TSADC
tristate "Freescale i.MX25 integrated Touchscreen and ADC unit"
select REGMAP_MMIO
@@ -425,18 +447,29 @@ config LPC_SCH
System Management Bus and General Purpose I/O.
config INTEL_SOC_PMIC
- bool "Support for Intel Atom SoC PMIC"
+ bool "Support for Crystal Cove PMIC"
depends on GPIOLIB
depends on I2C=y
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
- Select this option to enable support for the PMIC device
+ Select this option to enable support for Crystal Cove PMIC
on some Intel SoC systems. The PMIC provides ADC, GPIO,
thermal, charger and related power management functions
on these systems.
+config INTEL_SOC_PMIC_BXTWC
+ tristate "Support for Intel Broxton Whiskey Cove PMIC"
+ depends on INTEL_PMC_IPC
+ select MFD_CORE
+ select REGMAP_IRQ
+ help
+ Select this option to enable support for Whiskey Cove PMIC
+ on Intel Broxton systems. The PMIC provides ADC, GPIO,
+ thermal, charger and related power management functions
+ on these systems.
+
config MFD_INTEL_LPSS
tristate
select COMMON_CLK
@@ -1164,6 +1197,18 @@ config MFD_LP8788
TI LP8788 PMU supports regulators, battery charger, RTC,
ADC, backlight driver and current sinks.
+config MFD_TI_LMU
+ tristate "TI Lighting Management Unit driver"
+ depends on I2C
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Say yes here to enable support for TI LMU chips.
+
+ TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697.
+ It consists of backlight, LED and regulator driver.
+ It provides consistent device controls for lighting functions.
+
config MFD_OMAP_USB_HOST
bool "TI OMAP USBHS core and TLL driver"
depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 31ce07611a6f..c16bf1ea0ea9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_MFD_ACT8945A) += act8945a.o
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
-obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
+cros_ec_core-objs := cros_ec.o
+cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o
+obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
@@ -125,6 +127,8 @@ obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
obj-$(CONFIG_MFD_LP3943) += lp3943.o
obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
+obj-$(CONFIG_MFD_TI_LMU) += ti-lmu.o
+
da9055-objs := da9055-core.o da9055-i2c.o
obj-$(CONFIG_MFD_DA9055) += da9055.o
obj-$(CONFIG_MFD_DA9062) += da9062-core.o
@@ -181,6 +185,7 @@ obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o
obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o
+obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o
obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
@@ -207,11 +212,12 @@ obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
-intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
+obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
+obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c
index 06e1f7fc5605..96e7d2cb7b89 100644
--- a/drivers/mfd/altera-a10sr.c
+++ b/drivers/mfd/altera-a10sr.c
@@ -33,6 +33,10 @@ static const struct mfd_cell altr_a10sr_subdev_info[] = {
.name = "altr_a10sr_gpio",
.of_compatible = "altr,a10sr-gpio",
},
+ {
+ .name = "altr_a10sr_reset",
+ .of_compatible = "altr,a10sr-reset",
+ },
};
static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg)
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index b6d4bc63c426..75488e65cd96 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -235,29 +235,25 @@ static irqreturn_t arizona_overclocked(int irq, void *data)
return IRQ_HANDLED;
}
+#define ARIZONA_REG_POLL_DELAY_US 7500
+
static int arizona_poll_reg(struct arizona *arizona,
- int timeout, unsigned int reg,
+ int timeout_ms, unsigned int reg,
unsigned int mask, unsigned int target)
{
unsigned int val = 0;
- int ret, i;
-
- for (i = 0; i < timeout; i++) {
- ret = regmap_read(arizona->regmap, reg, &val);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to read reg %u: %d\n",
- reg, ret);
- continue;
- }
-
- if ((val & mask) == target)
- return 0;
+ int ret;
- usleep_range(1000, 5000);
- }
+ ret = regmap_read_poll_timeout(arizona->regmap,
+ ARIZONA_INTERRUPT_RAW_STATUS_5, val,
+ ((val & mask) == target),
+ ARIZONA_REG_POLL_DELAY_US,
+ timeout_ms * 1000);
+ if (ret)
+ dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n",
+ reg, val);
- dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val);
- return -ETIMEDOUT;
+ return ret;
}
static int arizona_wait_for_boot(struct arizona *arizona)
@@ -269,7 +265,7 @@ static int arizona_wait_for_boot(struct arizona *arizona)
* we won't race with the interrupt handler as it'll be blocked on
* runtime resume.
*/
- ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5,
+ ret = arizona_poll_reg(arizona, 30, ARIZONA_INTERRUPT_RAW_STATUS_5,
ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS);
if (!ret)
@@ -339,13 +335,11 @@ static int arizona_enable_freerun_sysclk(struct arizona *arizona,
ret);
return ret;
}
- ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5,
+ ret = arizona_poll_reg(arizona, 180, ARIZONA_INTERRUPT_RAW_STATUS_5,
ARIZONA_FLL1_CLOCK_OK_STS,
ARIZONA_FLL1_CLOCK_OK_STS);
- if (ret) {
- ret = -ETIMEDOUT;
+ if (ret)
goto err_fll;
- }
ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144);
if (ret) {
@@ -405,13 +399,11 @@ static int wm5102_apply_hardware_patch(struct arizona *arizona)
goto err;
}
- ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1,
+ ret = arizona_poll_reg(arizona, 30, ARIZONA_WRITE_SEQUENCER_CTRL_1,
ARIZONA_WSEQ_BUSY, 0);
- if (ret) {
+ if (ret)
regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
ARIZONA_WSEQ_ABORT);
- ret = -ETIMEDOUT;
- }
err:
err = arizona_disable_freerun_sysclk(arizona, &state);
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 0413c8159551..cf2e25ab2940 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -78,7 +78,7 @@ struct asic3 {
unsigned int bus_shift;
unsigned int irq_nr;
unsigned int irq_base;
- spinlock_t lock;
+ raw_spinlock_t lock;
u16 irq_bothedge[4];
struct gpio_chip gpio;
struct device *dev;
@@ -108,14 +108,14 @@ static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
unsigned long flags;
u32 val;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, reg);
if (set)
val |= bits;
else
val &= ~bits;
asic3_write_register(asic, reg, val);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
/* IRQs */
@@ -129,13 +129,13 @@ static void asic3_irq_flip_edge(struct asic3 *asic,
u16 edge;
unsigned long flags;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
edge = asic3_read_register(asic,
base + ASIC3_GPIO_EDGE_TRIGGER);
edge ^= bit;
asic3_write_register(asic,
base + ASIC3_GPIO_EDGE_TRIGGER, edge);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static void asic3_irq_demux(struct irq_desc *desc)
@@ -151,10 +151,10 @@ static void asic3_irq_demux(struct irq_desc *desc)
u32 status;
int bank;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
status = asic3_read_register(asic,
ASIC3_OFFSET(INTR, P_INT_STAT));
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
/* Check all ten register bits */
if ((status & 0x3ff) == 0)
@@ -167,7 +167,7 @@ static void asic3_irq_demux(struct irq_desc *desc)
base = ASIC3_GPIO_A_BASE
+ bank * ASIC3_GPIO_BASE_INCR;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
istat = asic3_read_register(asic,
base +
ASIC3_GPIO_INT_STATUS);
@@ -175,7 +175,7 @@ static void asic3_irq_demux(struct irq_desc *desc)
asic3_write_register(asic,
base +
ASIC3_GPIO_INT_STATUS, 0);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) {
int bit = (1 << i);
@@ -230,11 +230,11 @@ static void asic3_mask_gpio_irq(struct irq_data *data)
bank = asic3_irq_to_bank(asic, data->irq);
index = asic3_irq_to_index(asic, data->irq);
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
val |= 1 << index;
asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static void asic3_mask_irq(struct irq_data *data)
@@ -243,7 +243,7 @@ static void asic3_mask_irq(struct irq_data *data)
int regval;
unsigned long flags;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
regval = asic3_read_register(asic,
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK);
@@ -255,7 +255,7 @@ static void asic3_mask_irq(struct irq_data *data)
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK,
regval);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static void asic3_unmask_gpio_irq(struct irq_data *data)
@@ -267,11 +267,11 @@ static void asic3_unmask_gpio_irq(struct irq_data *data)
bank = asic3_irq_to_bank(asic, data->irq);
index = asic3_irq_to_index(asic, data->irq);
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
val &= ~(1 << index);
asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static void asic3_unmask_irq(struct irq_data *data)
@@ -280,7 +280,7 @@ static void asic3_unmask_irq(struct irq_data *data)
int regval;
unsigned long flags;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
regval = asic3_read_register(asic,
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK);
@@ -292,7 +292,7 @@ static void asic3_unmask_irq(struct irq_data *data)
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK,
regval);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
@@ -306,7 +306,7 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
index = asic3_irq_to_index(asic, data->irq);
bit = 1<<index;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
level = asic3_read_register(asic,
bank + ASIC3_GPIO_LEVEL_TRIGGER);
edge = asic3_read_register(asic,
@@ -348,7 +348,7 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
edge);
asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE,
trigger);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
return 0;
}
@@ -455,7 +455,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip,
return -EINVAL;
}
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION);
@@ -467,7 +467,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip,
asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
return 0;
@@ -524,7 +524,7 @@ static void asic3_gpio_set(struct gpio_chip *chip,
mask = ASIC3_GPIO_TO_MASK(offset);
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT);
@@ -535,7 +535,7 @@ static void asic3_gpio_set(struct gpio_chip *chip,
asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg);
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -611,13 +611,13 @@ static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
unsigned long flags;
u32 cdex;
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
if (clk->enabled++ == 0) {
cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
cdex |= clk->cdex;
asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
}
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
@@ -627,13 +627,13 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
WARN_ON(clk->enabled == 0);
- spin_lock_irqsave(&asic->lock, flags);
+ raw_spin_lock_irqsave(&asic->lock, flags);
if (--clk->enabled == 0) {
cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
cdex &= ~clk->cdex;
asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
}
- spin_unlock_irqrestore(&asic->lock, flags);
+ raw_spin_unlock_irqrestore(&asic->lock, flags);
}
/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */
@@ -963,7 +963,7 @@ static int __init asic3_probe(struct platform_device *pdev)
if (!asic)
return -ENOMEM;
- spin_lock_init(&asic->lock);
+ raw_spin_lock_init(&asic->lock);
platform_set_drvdata(pdev, asic);
asic->dev = &pdev->dev;
diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c
new file mode 100644
index 000000000000..954cf0f66a31
--- /dev/null
+++ b/drivers/mfd/atmel-smc.c
@@ -0,0 +1,314 @@
+/*
+ * Atmel SMC (Static Memory Controller) helper functions.
+ *
+ * Copyright (C) 2017 Atmel
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.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/mfd/syscon/atmel-smc.h>
+
+/**
+ * atmel_smc_cs_conf_init - initialize a SMC CS conf
+ * @conf: the SMC CS conf to initialize
+ *
+ * Set all fields to 0 so that one can start defining a new config.
+ */
+void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf)
+{
+ memset(conf, 0, sizeof(*conf));
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init);
+
+/**
+ * atmel_smc_cs_encode_ncycles - encode a number of MCK clk cycles in the
+ * format expected by the SMC engine
+ * @ncycles: number of MCK clk cycles
+ * @msbpos: position of the MSB part of the timing field
+ * @msbwidth: width of the MSB part of the timing field
+ * @msbfactor: factor applied to the MSB
+ * @encodedval: param used to store the encoding result
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Setup/Pulse/Cycle/Timings Register"). This is a generic
+ * helper which called with different parameter depending on the encoding
+ * scheme.
+ *
+ * If the @ncycles value is too big to be encoded, -ERANGE is returned and
+ * the encodedval is contains the maximum val. Otherwise, 0 is returned.
+ */
+static int atmel_smc_cs_encode_ncycles(unsigned int ncycles,
+ unsigned int msbpos,
+ unsigned int msbwidth,
+ unsigned int msbfactor,
+ unsigned int *encodedval)
+{
+ unsigned int lsbmask = GENMASK(msbpos - 1, 0);
+ unsigned int msbmask = GENMASK(msbwidth - 1, 0);
+ unsigned int msb, lsb;
+ int ret = 0;
+
+ msb = ncycles / msbfactor;
+ lsb = ncycles % msbfactor;
+
+ if (lsb > lsbmask) {
+ lsb = 0;
+ msb++;
+ }
+
+ /*
+ * Let's just put the maximum we can if the requested setting does
+ * not fit in the register field.
+ * We still return -ERANGE in case the caller cares.
+ */
+ if (msb > msbmask) {
+ msb = msbmask;
+ lsb = lsbmask;
+ ret = -ERANGE;
+ }
+
+ *encodedval = (msb << msbpos) | lsb;
+
+ return ret;
+}
+
+/**
+ * atmel_smc_cs_conf_set_timing - set the SMC CS conf Txx parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the Txx field in the TIMINGS register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this Txx
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Timings Register"), and then stores the result in the
+ * @conf->timings field at @shift position.
+ *
+ * Returns -EINVAL if shift is invalid, -ERANGE if ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "HSMC Timings
+ * Register"):
+ *
+ * ncycles = (Txx[3] * 64) + Txx[2:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val);
+ conf->timings &= ~GENMASK(shift + 3, shift);
+ conf->timings |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing);
+
+/**
+ * atmel_smc_cs_conf_set_setup - set the SMC CS conf xx_SETUP parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_SETUP field in the SETUP register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_SETUP
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Setup Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
+ shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "SMC Setup
+ * Register"):
+ *
+ * ncycles = (128 * xx_SETUP[5]) + xx_SETUP[4:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val);
+ conf->setup &= ~GENMASK(shift + 7, shift);
+ conf->setup |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup);
+
+/**
+ * atmel_smc_cs_conf_set_pulse - set the SMC CS conf xx_PULSE parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_PULSE field in the PULSE register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_PULSE
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Pulse Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
+ shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "SMC Pulse
+ * Register"):
+ *
+ * ncycles = (256 * xx_PULSE[6]) + xx_PULSE[5:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val);
+ conf->pulse &= ~GENMASK(shift + 7, shift);
+ conf->pulse |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse);
+
+/**
+ * atmel_smc_cs_conf_set_cycle - set the SMC CS conf xx_CYCLE parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_CYCLE field in the CYCLE register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_CYCLE
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Pulse Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "SMC Cycle
+ * Register"):
+ *
+ * ncycles = (xx_CYCLE[8:7] * 256) + xx_CYCLE[6:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val);
+ conf->cycle &= ~GENMASK(shift + 15, shift);
+ conf->cycle |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle);
+
+/**
+ * atmel_smc_cs_conf_apply - apply an SMC CS conf
+ * @regmap: the SMC regmap
+ * @cs: the CS id
+ * @conf the SMC CS conf to apply
+ *
+ * Applies an SMC CS configuration.
+ * Only valid on at91sam9/avr32 SoCs.
+ */
+void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs,
+ const struct atmel_smc_cs_conf *conf)
+{
+ regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup);
+ regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse);
+ regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle);
+ regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
+
+/**
+ * atmel_hsmc_cs_conf_apply - apply an SMC CS conf
+ * @regmap: the HSMC regmap
+ * @cs: the CS id
+ * @conf the SMC CS conf to apply
+ *
+ * Applies an SMC CS configuration.
+ * Only valid on post-sama5 SoCs.
+ */
+void atmel_hsmc_cs_conf_apply(struct regmap *regmap, int cs,
+ const struct atmel_smc_cs_conf *conf)
+{
+ regmap_write(regmap, ATMEL_HSMC_SETUP(cs), conf->setup);
+ regmap_write(regmap, ATMEL_HSMC_PULSE(cs), conf->pulse);
+ regmap_write(regmap, ATMEL_HSMC_CYCLE(cs), conf->cycle);
+ regmap_write(regmap, ATMEL_HSMC_TIMINGS(cs), conf->timings);
+ regmap_write(regmap, ATMEL_HSMC_MODE(cs), conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply);
+
+/**
+ * atmel_smc_cs_conf_get - retrieve the current SMC CS conf
+ * @regmap: the SMC regmap
+ * @cs: the CS id
+ * @conf: the SMC CS conf object to store the current conf
+ *
+ * Retrieve the SMC CS configuration.
+ * Only valid on at91sam9/avr32 SoCs.
+ */
+void atmel_smc_cs_conf_get(struct regmap *regmap, int cs,
+ struct atmel_smc_cs_conf *conf)
+{
+ regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup);
+ regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse);
+ regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle);
+ regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get);
+
+/**
+ * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf
+ * @regmap: the HSMC regmap
+ * @cs: the CS id
+ * @conf: the SMC CS conf object to store the current conf
+ *
+ * Retrieve the SMC CS configuration.
+ * Only valid on post-sama5 SoCs.
+ */
+void atmel_hsmc_cs_conf_get(struct regmap *regmap, int cs,
+ struct atmel_smc_cs_conf *conf)
+{
+ regmap_read(regmap, ATMEL_HSMC_SETUP(cs), &conf->setup);
+ regmap_read(regmap, ATMEL_HSMC_PULSE(cs), &conf->pulse);
+ regmap_read(regmap, ATMEL_HSMC_CYCLE(cs), &conf->cycle);
+ regmap_read(regmap, ATMEL_HSMC_TIMINGS(cs), &conf->timings);
+ regmap_read(regmap, ATMEL_HSMC_MODE(cs), &conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get);
diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
index a732cb50bcff..fd5c7267b136 100644
--- a/drivers/mfd/axp20x-rsb.c
+++ b/drivers/mfd/axp20x-rsb.c
@@ -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,axp803", .data = (void *)AXP803_ID },
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
{ .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
{ },
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 25115fe2acdf..1dc6235778eb 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -31,6 +31,7 @@
#define AXP20X_OFF 0x80
+#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE 0
#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
static const char * const axp20x_model_names[] = {
@@ -40,6 +41,7 @@ static const char * const axp20x_model_names[] = {
"AXP221",
"AXP223",
"AXP288",
+ "AXP803",
"AXP806",
"AXP809",
};
@@ -67,6 +69,7 @@ static const struct regmap_access_table axp152_volatile_table = {
static const struct regmap_range axp20x_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
+ regmap_reg_range(AXP20X_CHRG_CTRL1, AXP20X_CHRG_CTRL2),
regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
regmap_reg_range(AXP20X_RDC_H, AXP20X_OCV(AXP20X_OCV_MAX)),
};
@@ -93,6 +96,7 @@ static const struct regmap_access_table axp20x_volatile_table = {
/* 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_CHRG_CTRL1, AXP22X_CHRG_CTRL3),
regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1),
};
@@ -100,7 +104,7 @@ static const struct regmap_range axp22x_volatile_ranges[] = {
regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
- regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
+ regmap_reg_range(AXP22X_PMIC_TEMP_H, AXP20X_IPSOUT_V_HIGH_L),
regmap_reg_range(AXP20X_FG_RES, AXP20X_FG_RES),
};
@@ -114,6 +118,7 @@ static const struct regmap_access_table axp22x_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp22x_volatile_ranges),
};
+/* AXP288 ranges are shared with the AXP803, as they cover the same range */
static const struct regmap_range axp288_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
@@ -261,6 +266,20 @@ static struct resource axp288_fuel_gauge_resources[] = {
},
};
+static struct resource axp803_pek_resources[] = {
+ {
+ .name = "PEK_DBR",
+ .start = AXP803_IRQ_PEK_RIS_EDGE,
+ .end = AXP803_IRQ_PEK_RIS_EDGE,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = "PEK_DBF",
+ .start = AXP803_IRQ_PEK_FAL_EDGE,
+ .end = AXP803_IRQ_PEK_FAL_EDGE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct resource axp809_pek_resources[] = {
{
.name = "PEK_DBR",
@@ -454,6 +473,43 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
};
+static const struct regmap_irq axp803_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP803, ACIN_OVER_V, 0, 7),
+ INIT_REGMAP_IRQ(AXP803, ACIN_PLUGIN, 0, 6),
+ INIT_REGMAP_IRQ(AXP803, ACIN_REMOVAL, 0, 5),
+ INIT_REGMAP_IRQ(AXP803, VBUS_OVER_V, 0, 4),
+ INIT_REGMAP_IRQ(AXP803, VBUS_PLUGIN, 0, 3),
+ INIT_REGMAP_IRQ(AXP803, VBUS_REMOVAL, 0, 2),
+ INIT_REGMAP_IRQ(AXP803, BATT_PLUGIN, 1, 7),
+ INIT_REGMAP_IRQ(AXP803, BATT_REMOVAL, 1, 6),
+ INIT_REGMAP_IRQ(AXP803, BATT_ENT_ACT_MODE, 1, 5),
+ INIT_REGMAP_IRQ(AXP803, BATT_EXIT_ACT_MODE, 1, 4),
+ INIT_REGMAP_IRQ(AXP803, CHARG, 1, 3),
+ INIT_REGMAP_IRQ(AXP803, CHARG_DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_HIGH, 2, 7),
+ INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_HIGH_END, 2, 6),
+ INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_LOW, 2, 5),
+ INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_LOW_END, 2, 4),
+ INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_HIGH, 2, 3),
+ INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_HIGH_END, 2, 2),
+ INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_LOW, 2, 1),
+ INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_LOW_END, 2, 0),
+ INIT_REGMAP_IRQ(AXP803, DIE_TEMP_HIGH, 3, 7),
+ INIT_REGMAP_IRQ(AXP803, GPADC, 3, 2),
+ INIT_REGMAP_IRQ(AXP803, LOW_PWR_LVL1, 3, 1),
+ INIT_REGMAP_IRQ(AXP803, LOW_PWR_LVL2, 3, 0),
+ INIT_REGMAP_IRQ(AXP803, TIMER, 4, 7),
+ INIT_REGMAP_IRQ(AXP803, PEK_RIS_EDGE, 4, 6),
+ INIT_REGMAP_IRQ(AXP803, PEK_FAL_EDGE, 4, 5),
+ INIT_REGMAP_IRQ(AXP803, PEK_SHORT, 4, 4),
+ INIT_REGMAP_IRQ(AXP803, PEK_LONG, 4, 3),
+ INIT_REGMAP_IRQ(AXP803, PEK_OVER_OFF, 4, 2),
+ INIT_REGMAP_IRQ(AXP803, GPIO1_INPUT, 4, 1),
+ INIT_REGMAP_IRQ(AXP803, GPIO0_INPUT, 4, 0),
+ INIT_REGMAP_IRQ(AXP803, BC_USB_CHNG, 5, 1),
+ INIT_REGMAP_IRQ(AXP803, MV_CHNG, 5, 0),
+};
+
static const struct regmap_irq axp806_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV1, 0, 0),
INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV2, 0, 1),
@@ -554,6 +610,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = {
};
+static const struct regmap_irq_chip axp803_regmap_irq_chip = {
+ .name = "axp803",
+ .status_base = AXP20X_IRQ1_STATE,
+ .ack_base = AXP20X_IRQ1_STATE,
+ .mask_base = AXP20X_IRQ1_EN,
+ .mask_invert = true,
+ .init_ack_masked = true,
+ .irqs = axp803_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp803_regmap_irqs),
+ .num_regs = 6,
+};
+
static const struct regmap_irq_chip axp806_regmap_irq_chip = {
.name = "axp806",
.status_base = AXP20X_IRQ1_STATE,
@@ -589,6 +657,11 @@ static struct mfd_cell axp20x_cells[] = {
}, {
.name = "axp20x-regulator",
}, {
+ .name = "axp20x-adc",
+ }, {
+ .name = "axp20x-battery-power-supply",
+ .of_compatible = "x-powers,axp209-battery-power-supply",
+ }, {
.name = "axp20x-ac-power-supply",
.of_compatible = "x-powers,axp202-ac-power-supply",
.num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources),
@@ -609,6 +682,16 @@ static struct mfd_cell axp221_cells[] = {
}, {
.name = "axp20x-regulator",
}, {
+ .name = "axp22x-adc"
+ }, {
+ .name = "axp20x-ac-power-supply",
+ .of_compatible = "x-powers,axp221-ac-power-supply",
+ .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources),
+ .resources = axp20x_ac_power_supply_resources,
+ }, {
+ .name = "axp20x-battery-power-supply",
+ .of_compatible = "x-powers,axp221-battery-power-supply",
+ }, {
.name = "axp20x-usb-power-supply",
.of_compatible = "x-powers,axp221-usb-power-supply",
.num_resources = ARRAY_SIZE(axp22x_usb_power_supply_resources),
@@ -622,8 +705,18 @@ static struct mfd_cell axp223_cells[] = {
.num_resources = ARRAY_SIZE(axp22x_pek_resources),
.resources = axp22x_pek_resources,
}, {
+ .name = "axp22x-adc",
+ }, {
+ .name = "axp20x-battery-power-supply",
+ .of_compatible = "x-powers,axp221-battery-power-supply",
+ }, {
.name = "axp20x-regulator",
}, {
+ .name = "axp20x-ac-power-supply",
+ .of_compatible = "x-powers,axp221-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,axp223-usb-power-supply",
.num_resources = ARRAY_SIZE(axp22x_usb_power_supply_resources),
@@ -750,6 +843,14 @@ static struct mfd_cell axp288_cells[] = {
},
};
+static struct mfd_cell axp803_cells[] = {
+ {
+ .name = "axp20x-pek",
+ .num_resources = ARRAY_SIZE(axp803_pek_resources),
+ .resources = axp803_pek_resources,
+ }
+};
+
static struct mfd_cell axp806_cells[] = {
{
.id = 2,
@@ -836,6 +937,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
axp20x->irq_flags = IRQF_TRIGGER_LOW;
break;
+ case AXP803_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp803_cells);
+ axp20x->cells = axp803_cells;
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ axp20x->regmap_irq_chip = &axp803_regmap_irq_chip;
+ break;
case AXP806_ID:
axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
axp20x->cells = axp806_cells;
@@ -877,15 +984,19 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
* the these device addressing bits (in the upper 4 bits of the
* registers) match.
*
- * Since we only support an AXP806 chained to an AXP809 in slave
- * mode, and there isn't any existing hardware which uses AXP806
- * in master mode, or has 2 AXP806s in the same system, we can
- * just program the register address extension to the slave mode
- * address.
+ * By default we support an AXP806 chained to an AXP809 in slave
+ * mode. Boards which use an AXP806 in master mode can set the
+ * property "x-powers,master-mode" to override the default.
*/
- if (axp20x->variant == AXP806_ID)
- regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
- AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+ if (axp20x->variant == AXP806_ID) {
+ if (of_property_read_bool(axp20x->dev->of_node,
+ "x-powers,master-mode"))
+ regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+ AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
+ else
+ regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+ AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+ }
ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags,
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 9b66a98ba4bf..d4a407e466b5 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -166,6 +166,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
dev_info(dev, "Chrome EC device registered\n");
+ cros_ec_acpi_install_gpe_handler(dev);
+
return 0;
fail_mfd:
@@ -179,6 +181,8 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
{
mfd_remove_devices(ec_dev->dev);
+ cros_ec_acpi_remove_gpe_handler();
+
return 0;
}
EXPORT_SYMBOL(cros_ec_remove);
@@ -190,9 +194,14 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
int ret;
u8 sleep_event;
- sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
- HOST_SLEEP_EVENT_S3_RESUME :
- HOST_SLEEP_EVENT_S0IX_RESUME;
+ if (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) {
+ sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND;
+ } else {
+ sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND;
+
+ /* Clearing the GPE status for any pending event */
+ cros_ec_acpi_clear_gpe();
+ }
ret = cros_ec_sleep_event(ec_dev, sleep_event);
if (ret < 0)
diff --git a/drivers/mfd/cros_ec_acpi_gpe.c b/drivers/mfd/cros_ec_acpi_gpe.c
new file mode 100644
index 000000000000..56d305dab2d4
--- /dev/null
+++ b/drivers/mfd/cros_ec_acpi_gpe.c
@@ -0,0 +1,103 @@
+/*
+ * ChromeOS EC multi-function device
+ *
+ * Copyright (C) 2017 Google, Inc
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * The ChromeOS EC multi function device is used to mux all the requests
+ * to the EC device for its multiple features: keyboard controller,
+ * battery charging and regulator control, firmware update.
+ */
+#include <linux/acpi.h>
+
+#define ACPI_LID_DEVICE "LID0"
+
+static int ec_wake_gpe = -EINVAL;
+
+/*
+ * This handler indicates to ACPI core that this GPE should stay enabled for
+ * lid to work in suspend to idle path.
+ */
+static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number,
+ void *data)
+{
+ return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+}
+
+/*
+ * Get ACPI GPE for LID0 device.
+ */
+static int cros_ec_get_ec_wake_gpe(struct device *dev)
+{
+ struct acpi_device *cros_acpi_dev;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ acpi_status status;
+ int ret;
+
+ cros_acpi_dev = ACPI_COMPANION(dev);
+
+ if (!cros_acpi_dev || !cros_acpi_dev->parent ||
+ !cros_acpi_dev->parent->handle)
+ return -EINVAL;
+
+ status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE,
+ &handle);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(handle, &adev);
+ if (ret)
+ return ret;
+
+ return adev->wakeup.gpe_number;
+}
+
+int cros_ec_acpi_install_gpe_handler(struct device *dev)
+{
+ acpi_status status;
+
+ ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev);
+
+ if (ec_wake_gpe < 0)
+ return ec_wake_gpe;
+
+ status = acpi_install_gpe_handler(NULL, ec_wake_gpe,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &cros_ec_gpe_handler, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe);
+
+ return 0;
+}
+
+void cros_ec_acpi_remove_gpe_handler(void)
+{
+ acpi_status status;
+
+ if (ec_wake_gpe < 0)
+ return;
+
+ status = acpi_remove_gpe_handler(NULL, ec_wake_gpe,
+ &cros_ec_gpe_handler);
+ if (ACPI_FAILURE(status))
+ pr_err("failed to remove gpe handler\n");
+}
+
+void cros_ec_acpi_clear_gpe(void)
+{
+ if (ec_wake_gpe < 0)
+ return;
+
+ acpi_clear_gpe(NULL, ec_wake_gpe);
+}
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index a518832ed5f5..c9714072e224 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -45,8 +45,11 @@
* on the other end and need to transfer ~256 bytes, then we need:
* 10 us/bit * ~10 bits/byte * ~256 bytes = ~25ms
*
- * We'll wait 4 times that to handle clock stretching and other
- * paranoia.
+ * We'll wait 8 times that to handle clock stretching and other
+ * paranoia. Note that some battery gas gauge ICs claim to have a
+ * clock stretch of 144ms in rare situations. That's incentive for
+ * not directly passing i2c through, but it's too late for that for
+ * existing hardware.
*
* It's pretty unlikely that we'll really see a 249 byte tunnel in
* anything other than testing. If this was more common we might
@@ -54,7 +57,7 @@
* wait loop. The 'flash write' command would be another candidate
* for this, clocking in at 2-3ms.
*/
-#define EC_MSG_DEADLINE_MS 100
+#define EC_MSG_DEADLINE_MS 200
/*
* Time between raising the SPI chip select (for the end of a
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 8f873866ea60..7f5e8be0a9ea 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -1,6 +1,6 @@
/*
- * Core, IRQ and I2C device driver for DA9062 PMIC
- * Copyright (C) 2015 Dialog Semiconductor Ltd.
+ * Core, IRQ and I2C device driver for DA9061 and DA9062 PMICs
+ * Copyright (C) 2015-2017 Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,6 +30,70 @@
#define DA9062_REG_EVENT_B_OFFSET 1
#define DA9062_REG_EVENT_C_OFFSET 2
+static struct regmap_irq da9061_irqs[] = {
+ /* EVENT A */
+ [DA9061_IRQ_ONKEY] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_NONKEY_MASK,
+ },
+ [DA9061_IRQ_WDG_WARN] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_WDG_WARN_MASK,
+ },
+ [DA9061_IRQ_SEQ_RDY] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_SEQ_RDY_MASK,
+ },
+ /* EVENT B */
+ [DA9061_IRQ_TEMP] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_TEMP_MASK,
+ },
+ [DA9061_IRQ_LDO_LIM] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_LDO_LIM_MASK,
+ },
+ [DA9061_IRQ_DVC_RDY] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_DVC_RDY_MASK,
+ },
+ [DA9061_IRQ_VDD_WARN] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_VDD_WARN_MASK,
+ },
+ /* EVENT C */
+ [DA9061_IRQ_GPI0] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI0_MASK,
+ },
+ [DA9061_IRQ_GPI1] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI1_MASK,
+ },
+ [DA9061_IRQ_GPI2] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI2_MASK,
+ },
+ [DA9061_IRQ_GPI3] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI3_MASK,
+ },
+ [DA9061_IRQ_GPI4] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI4_MASK,
+ },
+};
+
+static struct regmap_irq_chip da9061_irq_chip = {
+ .name = "da9061-irq",
+ .irqs = da9061_irqs,
+ .num_irqs = DA9061_NUM_IRQ,
+ .num_regs = 3,
+ .status_base = DA9062AA_EVENT_A,
+ .mask_base = DA9062AA_IRQ_MASK_A,
+ .ack_base = DA9062AA_EVENT_A,
+};
+
static struct regmap_irq da9062_irqs[] = {
/* EVENT A */
[DA9062_IRQ_ONKEY] = {
@@ -102,6 +166,57 @@ static struct regmap_irq_chip da9062_irq_chip = {
.ack_base = DA9062AA_EVENT_A,
};
+static struct resource da9061_core_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_VDD_WARN, "VDD_WARN"),
+};
+
+static struct resource da9061_regulators_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_LDO_LIM, "LDO_LIM"),
+};
+
+static struct resource da9061_thermal_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_TEMP, "THERMAL"),
+};
+
+static struct resource da9061_wdt_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_WDG_WARN, "WD_WARN"),
+};
+
+static struct resource da9061_onkey_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_ONKEY, "ONKEY"),
+};
+
+static const struct mfd_cell da9061_devs[] = {
+ {
+ .name = "da9061-core",
+ .num_resources = ARRAY_SIZE(da9061_core_resources),
+ .resources = da9061_core_resources,
+ },
+ {
+ .name = "da9062-regulators",
+ .num_resources = ARRAY_SIZE(da9061_regulators_resources),
+ .resources = da9061_regulators_resources,
+ },
+ {
+ .name = "da9061-watchdog",
+ .num_resources = ARRAY_SIZE(da9061_wdt_resources),
+ .resources = da9061_wdt_resources,
+ .of_compatible = "dlg,da9061-watchdog",
+ },
+ {
+ .name = "da9061-thermal",
+ .num_resources = ARRAY_SIZE(da9061_thermal_resources),
+ .resources = da9061_thermal_resources,
+ .of_compatible = "dlg,da9061-thermal",
+ },
+ {
+ .name = "da9061-onkey",
+ .num_resources = ARRAY_SIZE(da9061_onkey_resources),
+ .resources = da9061_onkey_resources,
+ .of_compatible = "dlg,da9061-onkey",
+ },
+};
+
static struct resource da9062_core_resources[] = {
DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
};
@@ -200,7 +315,8 @@ static int da9062_clear_fault_log(struct da9062 *chip)
static int da9062_get_device_type(struct da9062 *chip)
{
- int device_id, variant_id, variant_mrc;
+ int device_id, variant_id, variant_mrc, variant_vrc;
+ char *type;
int ret;
ret = regmap_read(chip->regmap, DA9062AA_DEVICE_ID, &device_id);
@@ -219,9 +335,23 @@ static int da9062_get_device_type(struct da9062 *chip)
return -EIO;
}
+ variant_vrc = (variant_id & DA9062AA_VRC_MASK) >> DA9062AA_VRC_SHIFT;
+
+ switch (variant_vrc) {
+ case DA9062_PMIC_VARIANT_VRC_DA9061:
+ type = "DA9061";
+ break;
+ case DA9062_PMIC_VARIANT_VRC_DA9062:
+ type = "DA9062";
+ break;
+ default:
+ type = "Unknown";
+ break;
+ }
+
dev_info(chip->dev,
- "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
- device_id, variant_id);
+ "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
+ device_id, variant_id, type);
variant_mrc = (variant_id & DA9062AA_MRC_MASK) >> DA9062AA_MRC_SHIFT;
@@ -234,6 +364,234 @@ static int da9062_get_device_type(struct da9062 *chip)
return ret;
}
+static const struct regmap_range da9061_aa_readable_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_STATUS_B,
+ }, {
+ .range_min = DA9062AA_STATUS_D,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_IRQ_MASK_A,
+ .range_max = DA9062AA_IRQ_MASK_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_GPIO_4,
+ }, {
+ .range_min = DA9062AA_GPIO_WKUP_MODE,
+ .range_max = DA9062AA_GPIO_OUT3_4,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_ID_4_3,
+ }, {
+ .range_min = DA9062AA_ID_12_11,
+ .range_max = DA9062AA_ID_16_15,
+ }, {
+ .range_min = DA9062AA_ID_22_21,
+ .range_max = DA9062AA_ID_32_31,
+ }, {
+ .range_min = DA9062AA_SEQ_A,
+ .range_max = DA9062AA_WAIT,
+ }, {
+ .range_min = DA9062AA_RESET,
+ .range_max = DA9062AA_BUCK_ILIM_C,
+ }, {
+ .range_min = DA9062AA_BUCK1_CFG,
+ .range_max = DA9062AA_BUCK3_CFG,
+ }, {
+ .range_min = DA9062AA_VBUCK1_A,
+ .range_max = DA9062AA_VBUCK4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK3_A,
+ .range_max = DA9062AA_VBUCK3_A,
+ }, {
+ .range_min = DA9062AA_VLDO1_A,
+ .range_max = DA9062AA_VLDO4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK1_B,
+ .range_max = DA9062AA_VBUCK4_B,
+ }, {
+ .range_min = DA9062AA_VBUCK3_B,
+ .range_max = DA9062AA_VBUCK3_B,
+ }, {
+ .range_min = DA9062AA_VLDO1_B,
+ .range_max = DA9062AA_VLDO4_B,
+ }, {
+ .range_min = DA9062AA_BBAT_CONT,
+ .range_max = DA9062AA_BBAT_CONT,
+ }, {
+ .range_min = DA9062AA_INTERFACE,
+ .range_max = DA9062AA_CONFIG_E,
+ }, {
+ .range_min = DA9062AA_CONFIG_G,
+ .range_max = DA9062AA_CONFIG_K,
+ }, {
+ .range_min = DA9062AA_CONFIG_M,
+ .range_max = DA9062AA_CONFIG_M,
+ }, {
+ .range_min = DA9062AA_GP_ID_0,
+ .range_max = DA9062AA_GP_ID_19,
+ }, {
+ .range_min = DA9062AA_DEVICE_ID,
+ .range_max = DA9062AA_CONFIG_ID,
+ },
+};
+
+static const struct regmap_range da9061_aa_writeable_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_PAGE_CON,
+ }, {
+ .range_min = DA9062AA_FAULT_LOG,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_IRQ_MASK_A,
+ .range_max = DA9062AA_IRQ_MASK_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_GPIO_4,
+ }, {
+ .range_min = DA9062AA_GPIO_WKUP_MODE,
+ .range_max = DA9062AA_GPIO_OUT3_4,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_ID_4_3,
+ }, {
+ .range_min = DA9062AA_ID_12_11,
+ .range_max = DA9062AA_ID_16_15,
+ }, {
+ .range_min = DA9062AA_ID_22_21,
+ .range_max = DA9062AA_ID_32_31,
+ }, {
+ .range_min = DA9062AA_SEQ_A,
+ .range_max = DA9062AA_WAIT,
+ }, {
+ .range_min = DA9062AA_RESET,
+ .range_max = DA9062AA_BUCK_ILIM_C,
+ }, {
+ .range_min = DA9062AA_BUCK1_CFG,
+ .range_max = DA9062AA_BUCK3_CFG,
+ }, {
+ .range_min = DA9062AA_VBUCK1_A,
+ .range_max = DA9062AA_VBUCK4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK3_A,
+ .range_max = DA9062AA_VBUCK3_A,
+ }, {
+ .range_min = DA9062AA_VLDO1_A,
+ .range_max = DA9062AA_VLDO4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK1_B,
+ .range_max = DA9062AA_VBUCK4_B,
+ }, {
+ .range_min = DA9062AA_VBUCK3_B,
+ .range_max = DA9062AA_VBUCK3_B,
+ }, {
+ .range_min = DA9062AA_VLDO1_B,
+ .range_max = DA9062AA_VLDO4_B,
+ }, {
+ .range_min = DA9062AA_BBAT_CONT,
+ .range_max = DA9062AA_BBAT_CONT,
+ }, {
+ .range_min = DA9062AA_GP_ID_0,
+ .range_max = DA9062AA_GP_ID_19,
+ },
+};
+
+static const struct regmap_range da9061_aa_volatile_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_STATUS_B,
+ }, {
+ .range_min = DA9062AA_STATUS_D,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_CONTROL_B,
+ }, {
+ .range_min = DA9062AA_CONTROL_E,
+ .range_max = DA9062AA_CONTROL_F,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_SEQ,
+ },
+};
+
+static const struct regmap_access_table da9061_aa_readable_table = {
+ .yes_ranges = da9061_aa_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_readable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_writeable_table = {
+ .yes_ranges = da9061_aa_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_writeable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_volatile_table = {
+ .yes_ranges = da9061_aa_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_volatile_ranges),
+};
+
+static const struct regmap_range_cfg da9061_range_cfg[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_CONFIG_ID,
+ .selector_reg = DA9062AA_PAGE_CON,
+ .selector_mask = 1 << DA9062_I2C_PAGE_SEL_SHIFT,
+ .selector_shift = DA9062_I2C_PAGE_SEL_SHIFT,
+ .window_start = 0,
+ .window_len = 256,
+ }
+};
+
+static struct regmap_config da9061_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .ranges = da9061_range_cfg,
+ .num_ranges = ARRAY_SIZE(da9061_range_cfg),
+ .max_register = DA9062AA_CONFIG_ID,
+ .cache_type = REGCACHE_RBTREE,
+ .rd_table = &da9061_aa_readable_table,
+ .wr_table = &da9061_aa_writeable_table,
+ .volatile_table = &da9061_aa_volatile_table,
+};
+
static const struct regmap_range da9062_aa_readable_ranges[] = {
{
.range_min = DA9062AA_PAGE_CON,
@@ -456,17 +814,39 @@ static struct regmap_config da9062_regmap_config = {
.volatile_table = &da9062_aa_volatile_table,
};
+static const struct of_device_id da9062_dt_ids[] = {
+ { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },
+ { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9062_dt_ids);
+
static int da9062_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct da9062 *chip;
+ const struct of_device_id *match;
unsigned int irq_base;
+ const struct mfd_cell *cell;
+ const struct regmap_irq_chip *irq_chip;
+ const struct regmap_config *config;
+ int cell_num;
int ret;
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ if (i2c->dev.of_node) {
+ match = of_match_node(da9062_dt_ids, i2c->dev.of_node);
+ if (!match)
+ return -EINVAL;
+
+ chip->chip_type = (uintptr_t)match->data;
+ } else {
+ chip->chip_type = id->driver_data;
+ }
+
i2c_set_clientdata(i2c, chip);
chip->dev = &i2c->dev;
@@ -475,7 +855,25 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
return -EINVAL;
}
- chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
+ switch (chip->chip_type) {
+ case COMPAT_TYPE_DA9061:
+ cell = da9061_devs;
+ cell_num = ARRAY_SIZE(da9061_devs);
+ irq_chip = &da9061_irq_chip;
+ config = &da9061_regmap_config;
+ break;
+ case COMPAT_TYPE_DA9062:
+ cell = da9062_devs;
+ cell_num = ARRAY_SIZE(da9062_devs);
+ irq_chip = &da9062_irq_chip;
+ config = &da9062_regmap_config;
+ break;
+ default:
+ dev_err(chip->dev, "Unrecognised chip type\n");
+ return -ENODEV;
+ }
+
+ chip->regmap = devm_regmap_init_i2c(i2c, config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(chip->dev, "Failed to allocate register map: %d\n",
@@ -493,7 +891,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
- -1, &da9062_irq_chip,
+ -1, irq_chip,
&chip->regmap_irq);
if (ret) {
dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
@@ -503,8 +901,8 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
irq_base = regmap_irq_chip_get_base(chip->regmap_irq);
- ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, da9062_devs,
- ARRAY_SIZE(da9062_devs), NULL, irq_base,
+ ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
+ cell_num, NULL, irq_base,
NULL);
if (ret) {
dev_err(chip->dev, "Cannot register child devices\n");
@@ -526,17 +924,12 @@ static int da9062_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id da9062_i2c_id[] = {
- { "da9062", 0 },
+ { "da9061", COMPAT_TYPE_DA9061 },
+ { "da9062", COMPAT_TYPE_DA9062 },
{ },
};
MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);
-static const struct of_device_id da9062_dt_ids[] = {
- { .compatible = "dlg,da9062", },
- { }
-};
-MODULE_DEVICE_TABLE(of, da9062_dt_ids);
-
static struct i2c_driver da9062_i2c_driver = {
.driver = {
.name = "da9062",
@@ -549,6 +942,6 @@ static struct i2c_driver da9062_i2c_driver = {
module_i2c_driver(da9062_i2c_driver);
-MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
+MODULE_DESCRIPTION("Core device driver for Dialog DA9061 and DA9062");
MODULE_AUTHOR("Steve Twiss <stwiss.opensource@diasemi.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index ca38a6a14110..5c739ac752e8 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -2377,7 +2377,7 @@ static void ack_dbb_wakeup(void)
static inline void print_unknown_header_warning(u8 n, u8 header)
{
- pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+ pr_warn("prcmu: Unknown message header (%d) in mailbox %d\n",
header, n);
}
diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c
index 2e064fb8826f..0bf3aebdac45 100644
--- a/drivers/mfd/exynos-lpass.c
+++ b/drivers/mfd/exynos-lpass.c
@@ -14,15 +14,17 @@
* only version 2 as published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/exynos5-pmu.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/types.h>
/* LPASS Top register definitions */
@@ -51,10 +53,9 @@
#define LPASS_INTR_SFR BIT(0)
struct exynos_lpass {
- /* pointer to the Power Management Unit regmap */
- struct regmap *pmu;
/* pointer to the LPASS TOP regmap */
struct regmap *top;
+ struct clk *sfr0_clk;
};
static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
@@ -74,6 +75,8 @@ static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
static void exynos_lpass_enable(struct exynos_lpass *lpass)
{
+ clk_prepare_enable(lpass->sfr0_clk);
+
/* Unmask SFR, DMA and I2S interrupt */
regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
@@ -81,10 +84,6 @@ static void exynos_lpass_enable(struct exynos_lpass *lpass)
regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
- /* Activate related PADs from retention state */
- regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION,
- EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR);
-
exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
@@ -96,8 +95,7 @@ static void exynos_lpass_disable(struct exynos_lpass *lpass)
regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
- /* Deactivate related PADs from retention state */
- regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION, 0);
+ clk_disable_unprepare(lpass->sfr0_clk);
}
static const struct regmap_config exynos_lpass_reg_conf = {
@@ -124,6 +122,10 @@ static int exynos_lpass_probe(struct platform_device *pdev)
if (IS_ERR(base_top))
return PTR_ERR(base_top);
+ lpass->sfr0_clk = devm_clk_get(dev, "sfr0_ctrl");
+ if (IS_ERR(lpass->sfr0_clk))
+ return PTR_ERR(lpass->sfr0_clk);
+
lpass->top = regmap_init_mmio(dev, base_top,
&exynos_lpass_reg_conf);
if (IS_ERR(lpass->top)) {
@@ -131,19 +133,27 @@ static int exynos_lpass_probe(struct platform_device *pdev)
return PTR_ERR(lpass->top);
}
- lpass->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
- "samsung,pmu-syscon");
- if (IS_ERR(lpass->pmu)) {
- dev_err(dev, "Failed to lookup PMU regmap\n");
- return PTR_ERR(lpass->pmu);
- }
-
platform_set_drvdata(pdev, lpass);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
exynos_lpass_enable(lpass);
return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
+static int exynos_lpass_remove(struct platform_device *pdev)
+{
+ struct exynos_lpass *lpass = platform_get_drvdata(pdev);
+
+ exynos_lpass_disable(lpass);
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ exynos_lpass_disable(lpass);
+ regmap_exit(lpass->top);
+
+ return 0;
+}
+
static int __maybe_unused exynos_lpass_suspend(struct device *dev)
{
struct exynos_lpass *lpass = dev_get_drvdata(dev);
@@ -162,8 +172,11 @@ static int __maybe_unused exynos_lpass_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(lpass_pm_ops, exynos_lpass_suspend,
- exynos_lpass_resume);
+static const struct dev_pm_ops lpass_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_lpass_suspend, exynos_lpass_resume, NULL)
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
static const struct of_device_id exynos_lpass_of_match[] = {
{ .compatible = "samsung,exynos5433-lpass" },
@@ -178,6 +191,7 @@ static struct platform_driver exynos_lpass_driver = {
.of_match_table = exynos_lpass_of_match,
},
.probe = exynos_lpass_probe,
+ .remove = exynos_lpass_remove,
};
module_platform_driver(exynos_lpass_driver);
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index ba706adee38b..c37ccbfd52f2 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -77,7 +77,8 @@ static const struct mfd_cell hi655x_pmic_devs[] = {
.num_resources = ARRAY_SIZE(pwrkey_resources),
.resources = &pwrkey_resources[0],
},
- { .name = "hi655x-regulator", },
+ { .name = "hi655x-regulator", },
+ { .name = "hi655x-clk", },
};
static void hi655x_local_irq_clear(struct regmap *map)
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index 6bf8d643d942..7911b0a14a6d 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -22,10 +22,6 @@
#include "intel-lpss.h"
-static const struct intel_lpss_platform_info spt_info = {
- .clk_rate = 120000000,
-};
-
static struct property_entry spt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
{ },
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 699c8c7c9052..8c3cbf63c6ad 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -20,7 +20,8 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
-#include <linux/mfd/intel_bxtwc.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/mfd/intel_soc_pmic_bxtwc.h>
#include <asm/intel_pmc_ipc.h>
/* PMIC device registers */
@@ -237,15 +238,14 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
u8 ipc_out[4];
struct intel_soc_pmic *pmic = context;
+ if (!pmic)
+ return -EINVAL;
+
if (reg & REG_ADDR_MASK)
i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
- else {
+ else
i2c_addr = BXTWC_DEVICE1_ADDR;
- if (!i2c_addr) {
- dev_err(pmic->dev, "I2C address not set\n");
- return -EINVAL;
- }
- }
+
reg &= REG_OFFSET_MASK;
ipc_in[0] = reg;
@@ -270,15 +270,14 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
u8 ipc_in[3];
struct intel_soc_pmic *pmic = context;
+ if (!pmic)
+ return -EINVAL;
+
if (reg & REG_ADDR_MASK)
i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
- else {
+ else
i2c_addr = BXTWC_DEVICE1_ADDR;
- if (!i2c_addr) {
- dev_err(pmic->dev, "I2C address not set\n");
- return -EINVAL;
- }
- }
+
reg &= REG_OFFSET_MASK;
ipc_in[0] = reg;
diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c
index 12d6ebb4ae5d..13737be6df35 100644
--- a/drivers/mfd/intel_soc_pmic_core.c
+++ b/drivers/mfd/intel_soc_pmic_core.c
@@ -44,22 +44,6 @@ static struct pwm_lookup crc_pwm_lookup[] = {
PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL),
};
-static int intel_soc_pmic_find_gpio_irq(struct device *dev)
-{
- struct gpio_desc *desc;
- int irq;
-
- desc = devm_gpiod_get_index(dev, "intel_soc_pmic", 0, GPIOD_IN);
- if (IS_ERR(desc))
- return PTR_ERR(desc);
-
- irq = gpiod_to_irq(desc);
- if (irq < 0)
- dev_warn(dev, "Can't get irq: %d\n", irq);
-
- return irq;
-}
-
static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
@@ -68,7 +52,6 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
struct intel_soc_pmic_config *config;
struct intel_soc_pmic *pmic;
int ret;
- int irq;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id || !id->driver_data)
@@ -83,14 +66,10 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
dev_set_drvdata(dev, pmic);
pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
+ if (IS_ERR(pmic->regmap))
+ return PTR_ERR(pmic->regmap);
- /*
- * On some boards the PMIC interrupt may come from a GPIO line. Try to
- * lookup the ACPI table for a such connection and setup a GPIO
- * interrupt if it exists. Otherwise use the IRQ provided by I2C
- */
- irq = intel_soc_pmic_find_gpio_irq(dev);
- pmic->irq = (irq < 0) ? i2c->irq : irq;
+ pmic->irq = i2c->irq;
ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
config->irq_flags | IRQF_ONESHOT,
diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c
index df16fd1df68b..124aad2b1d02 100644
--- a/drivers/mfd/ipaq-micro.c
+++ b/drivers/mfd/ipaq-micro.c
@@ -400,9 +400,6 @@ static int __init micro_probe(struct platform_device *pdev)
micro->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
micro->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(micro->base))
return PTR_ERR(micro->base);
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index d98a5d974092..773f1554d2f9 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -227,6 +227,8 @@ enum lpc_chipsets {
LPC_LEWISBURG, /* Lewisburg */
LPC_9S, /* 9 Series */
LPC_APL, /* Apollo Lake SoC */
+ LPC_GLK, /* Gemini Lake SoC */
+ LPC_COUGARMOUNTAIN,/* Cougar Mountain SoC*/
};
static struct lpc_ich_info lpc_chipset_info[] = {
@@ -554,6 +556,14 @@ static struct lpc_ich_info lpc_chipset_info[] = {
.iTCO_version = 5,
.spi_type = INTEL_SPI_BXT,
},
+ [LPC_GLK] = {
+ .name = "Gemini Lake SoC",
+ .spi_type = INTEL_SPI_BXT,
+ },
+ [LPC_COUGARMOUNTAIN] = {
+ .name = "Cougar Mountain SoC",
+ .iTCO_version = 3,
+ },
};
/*
@@ -682,6 +692,8 @@ static const struct pci_device_id lpc_ich_ids[] = {
{ PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME},
{ PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9},
{ PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M},
+ { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK},
+ { PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN},
{ PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO},
{ PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R},
{ PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10},
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index a4a8f1ec3fb6..29b7164a823b 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -1022,9 +1022,7 @@ static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w)
static void menelaus_rtc_update_work(struct menelaus_chip *m)
{
/* report 1/sec update */
- local_irq_disable();
rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF);
- local_irq_enable();
}
static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
@@ -1086,9 +1084,7 @@ static const struct rtc_class_ops menelaus_rtc_ops = {
static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
{
/* report alarm */
- local_irq_disable();
rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF);
- local_irq_enable();
/* then disable it; alarms are oneshot */
the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 6aeada7d7ce5..3cab58ab0b84 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -23,6 +23,8 @@
#define CPCAP_NR_IRQ_REG_BANKS 6
#define CPCAP_NR_IRQ_CHIPS 3
+#define CPCAP_REGISTER_SIZE 4
+#define CPCAP_REGISTER_BITS 16
struct cpcap_ddata {
struct spi_device *spi;
@@ -32,6 +34,32 @@ struct cpcap_ddata {
struct regmap *regmap;
};
+static int cpcap_sense_irq(struct regmap *regmap, int irq)
+{
+ int regnum = irq / CPCAP_REGISTER_BITS;
+ int mask = BIT(irq % CPCAP_REGISTER_BITS);
+ int reg = CPCAP_REG_INTS1 + (regnum * CPCAP_REGISTER_SIZE);
+ int err, val;
+
+ if (reg < CPCAP_REG_INTS1 || reg > CPCAP_REG_INTS4)
+ return -EINVAL;
+
+ err = regmap_read(regmap, reg, &val);
+ if (err)
+ return err;
+
+ return !!(val & mask);
+}
+
+int cpcap_sense_virq(struct regmap *regmap, int virq)
+{
+ struct regmap_irq_chip_data *d = irq_get_chip_data(virq);
+ int irq_base = regmap_irq_chip_get_base(d);
+
+ return cpcap_sense_irq(regmap, virq - irq_base);
+}
+EXPORT_SYMBOL_GPL(cpcap_sense_virq);
+
static int cpcap_check_revision(struct cpcap_ddata *cpcap)
{
u16 vendor, rev;
@@ -71,6 +99,7 @@ static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
.ack_base = CPCAP_REG_MI1,
.mask_base = CPCAP_REG_MIM1,
.use_ack = true,
+ .ack_invert = true,
},
{
.name = "cpcap-m2",
@@ -79,6 +108,7 @@ static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
.ack_base = CPCAP_REG_MI2,
.mask_base = CPCAP_REG_MIM2,
.use_ack = true,
+ .ack_invert = true,
},
{
.name = "cpcap1-4",
@@ -86,8 +116,8 @@ static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
.status_base = CPCAP_REG_INT1,
.ack_base = CPCAP_REG_INT1,
.mask_base = CPCAP_REG_INTM1,
- .type_base = CPCAP_REG_INTS1,
.use_ack = true,
+ .ack_invert = true,
},
};
@@ -126,7 +156,7 @@ static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip,
ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap,
cpcap->spi->irq,
- IRQF_TRIGGER_RISING |
+ irq_get_trigger_type(cpcap->spi->irq) |
IRQF_SHARED, -1,
chip, &cpcap->irqdata[irq_chip]);
if (ret) {
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 8e601c846d08..04a601f6aebe 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -47,8 +47,7 @@ static const struct mfd_cell mt6323_devs[] = {
{
.name = "mt6323-regulator",
.of_compatible = "mediatek,mt6323-regulator"
- },
- {
+ }, {
.name = "mt6323-led",
.of_compatible = "mediatek,mt6323-led"
},
diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c
new file mode 100644
index 000000000000..630bd19b2c0a
--- /dev/null
+++ b/drivers/mfd/mxs-lradc.c
@@ -0,0 +1,267 @@
+/*
+ * Freescale MXS Low Resolution Analog-to-Digital Converter driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+ *
+ * Authors:
+ * Marek Vasut <marex@denx.de>
+ * Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mxs-lradc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define ADC_CELL 0
+#define TSC_CELL 1
+#define RES_MEM 0
+
+enum mx23_lradc_irqs {
+ MX23_LRADC_TS_IRQ = 0,
+ MX23_LRADC_CH0_IRQ,
+ MX23_LRADC_CH1_IRQ,
+ MX23_LRADC_CH2_IRQ,
+ MX23_LRADC_CH3_IRQ,
+ MX23_LRADC_CH4_IRQ,
+ MX23_LRADC_CH5_IRQ,
+ MX23_LRADC_CH6_IRQ,
+ MX23_LRADC_CH7_IRQ,
+};
+
+enum mx28_lradc_irqs {
+ MX28_LRADC_TS_IRQ = 0,
+ MX28_LRADC_TRESH0_IRQ,
+ MX28_LRADC_TRESH1_IRQ,
+ MX28_LRADC_CH0_IRQ,
+ MX28_LRADC_CH1_IRQ,
+ MX28_LRADC_CH2_IRQ,
+ MX28_LRADC_CH3_IRQ,
+ MX28_LRADC_CH4_IRQ,
+ MX28_LRADC_CH5_IRQ,
+ MX28_LRADC_CH6_IRQ,
+ MX28_LRADC_CH7_IRQ,
+ MX28_LRADC_BUTTON0_IRQ,
+ MX28_LRADC_BUTTON1_IRQ,
+};
+
+static struct resource mx23_adc_resources[] = {
+ DEFINE_RES_MEM(0x0, 0x0),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH0_IRQ, "mxs-lradc-channel0"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH1_IRQ, "mxs-lradc-channel1"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH2_IRQ, "mxs-lradc-channel2"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH3_IRQ, "mxs-lradc-channel3"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH4_IRQ, "mxs-lradc-channel4"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH5_IRQ, "mxs-lradc-channel5"),
+};
+
+static struct resource mx23_touchscreen_resources[] = {
+ DEFINE_RES_MEM(0x0, 0x0),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_TS_IRQ, "mxs-lradc-touchscreen"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH6_IRQ, "mxs-lradc-channel6"),
+ DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH7_IRQ, "mxs-lradc-channel7"),
+};
+
+static struct resource mx28_adc_resources[] = {
+ DEFINE_RES_MEM(0x0, 0x0),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_TRESH0_IRQ, "mxs-lradc-thresh0"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_TRESH1_IRQ, "mxs-lradc-thresh1"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH0_IRQ, "mxs-lradc-channel0"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH1_IRQ, "mxs-lradc-channel1"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH2_IRQ, "mxs-lradc-channel2"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH3_IRQ, "mxs-lradc-channel3"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH4_IRQ, "mxs-lradc-channel4"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH5_IRQ, "mxs-lradc-channel5"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_BUTTON0_IRQ, "mxs-lradc-button0"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_BUTTON1_IRQ, "mxs-lradc-button1"),
+};
+
+static struct resource mx28_touchscreen_resources[] = {
+ DEFINE_RES_MEM(0x0, 0x0),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_TS_IRQ, "mxs-lradc-touchscreen"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH6_IRQ, "mxs-lradc-channel6"),
+ DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH7_IRQ, "mxs-lradc-channel7"),
+};
+
+static struct mfd_cell mx23_cells[] = {
+ {
+ .name = "mxs-lradc-adc",
+ .resources = mx23_adc_resources,
+ .num_resources = ARRAY_SIZE(mx23_adc_resources),
+ },
+ {
+ .name = "mxs-lradc-ts",
+ .resources = mx23_touchscreen_resources,
+ .num_resources = ARRAY_SIZE(mx23_touchscreen_resources),
+ },
+};
+
+static struct mfd_cell mx28_cells[] = {
+ {
+ .name = "mxs-lradc-adc",
+ .resources = mx28_adc_resources,
+ .num_resources = ARRAY_SIZE(mx28_adc_resources),
+ },
+ {
+ .name = "mxs-lradc-ts",
+ .resources = mx28_touchscreen_resources,
+ .num_resources = ARRAY_SIZE(mx28_touchscreen_resources),
+ }
+};
+
+static const struct of_device_id mxs_lradc_dt_ids[] = {
+ { .compatible = "fsl,imx23-lradc", .data = (void *)IMX23_LRADC, },
+ { .compatible = "fsl,imx28-lradc", .data = (void *)IMX28_LRADC, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
+
+static int mxs_lradc_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct mxs_lradc *lradc;
+ struct mfd_cell *cells = NULL;
+ struct resource *res;
+ int ret = 0;
+ u32 ts_wires = 0;
+
+ lradc = devm_kzalloc(&pdev->dev, sizeof(*lradc), GFP_KERNEL);
+ if (!lradc)
+ return -ENOMEM;
+
+ of_id = of_match_device(mxs_lradc_dt_ids, &pdev->dev);
+ if (!of_id)
+ return -EINVAL;
+
+ lradc->soc = (enum mxs_lradc_id)of_id->data;
+
+ lradc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(lradc->clk)) {
+ dev_err(dev, "Failed to get the delay unit clock\n");
+ return PTR_ERR(lradc->clk);
+ }
+
+ ret = clk_prepare_enable(lradc->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable the delay unit clock\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires",
+ &ts_wires);
+
+ if (!ret) {
+ lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
+
+ switch (ts_wires) {
+ case 4:
+ lradc->touchscreen_wire = MXS_LRADC_TOUCHSCREEN_4WIRE;
+ break;
+ case 5:
+ if (lradc->soc == IMX28_LRADC) {
+ lradc->touchscreen_wire =
+ MXS_LRADC_TOUCHSCREEN_5WIRE;
+ break;
+ }
+ /* fall through to an error message for i.MX23 */
+ default:
+ dev_err(&pdev->dev,
+ "Unsupported number of touchscreen wires (%d)\n"
+ , ts_wires);
+ ret = -EINVAL;
+ goto err_clk;
+ }
+ } else {
+ lradc->buffer_vchans = BUFFER_VCHANS_ALL;
+ }
+
+ platform_set_drvdata(pdev, lradc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOMEM;
+
+ switch (lradc->soc) {
+ case IMX23_LRADC:
+ mx23_adc_resources[RES_MEM] = *res;
+ mx23_touchscreen_resources[RES_MEM] = *res;
+ cells = mx23_cells;
+ break;
+ case IMX28_LRADC:
+ mx28_adc_resources[RES_MEM] = *res;
+ mx28_touchscreen_resources[RES_MEM] = *res;
+ cells = mx28_cells;
+ break;
+ default:
+ dev_err(dev, "Unsupported SoC\n");
+ ret = -ENODEV;
+ goto err_clk;
+ }
+
+ ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+ &cells[ADC_CELL], 1, NULL, 0, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add the ADC subdevice\n");
+ goto err_clk;
+ }
+
+ if (!lradc->touchscreen_wire)
+ return 0;
+
+ ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+ &cells[TSC_CELL], 1, NULL, 0, NULL);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to add the touchscreen subdevice\n");
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(lradc->clk);
+
+ return ret;
+}
+
+static int mxs_lradc_remove(struct platform_device *pdev)
+{
+ struct mxs_lradc *lradc = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(lradc->clk);
+
+ return 0;
+}
+
+static struct platform_driver mxs_lradc_driver = {
+ .driver = {
+ .name = "mxs-lradc",
+ .of_match_table = mxs_lradc_dt_ids,
+ },
+ .probe = mxs_lradc_probe,
+ .remove = mxs_lradc_remove,
+};
+module_platform_driver(mxs_lradc_driver);
+
+MODULE_AUTHOR("Ksenija Stanojevic <ksenija.stanojevic@gmail.com>");
+MODULE_DESCRIPTION("Freescale i.MX23/i.MX28 LRADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-lradc");
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c
index 1aa74c4c3ced..6f5300b0eb31 100644
--- a/drivers/mfd/omap-usb-tll.c
+++ b/drivers/mfd/omap-usb-tll.c
@@ -373,12 +373,13 @@ int omap_tll_init(struct usbhs_omap_platform_data *pdata)
} else if (pdata->port_mode[i] ==
OMAP_EHCI_PORT_MODE_TLL) {
/*
- * Disable AutoIdle, BitStuffing
- * and use SDR Mode
+ * Disable UTMI AutoIdle, BitStuffing
+ * and use SDR Mode. Enable ULPI AutoIdle.
*/
reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
- | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
+ reg |= OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
+ reg |= OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE;
} else if (pdata->port_mode[i] ==
OMAP_EHCI_PORT_MODE_HSIC) {
/*
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index ee9e9ea10444..9103affedcbc 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -430,6 +430,20 @@ static void palmas_power_off(void)
{
unsigned int addr;
int ret, slave;
+ struct device_node *np = palmas_dev->dev->of_node;
+
+ if (of_property_read_bool(np, "ti,palmas-override-powerhold")) {
+ addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+ PALMAS_PRIMARY_SECONDARY_PAD2);
+ slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
+
+ ret = regmap_update_bits(palmas_dev->regmap[slave], addr,
+ PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK, 0);
+ if (ret)
+ dev_err(palmas_dev->dev,
+ "Unable to write PRIMARY_SECONDARY_PAD2 %d\n",
+ ret);
+ }
slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL);
@@ -567,7 +581,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
PALMAS_POLARITY_CTRL, PALMAS_POLARITY_CTRL_INT_POLARITY,
reg);
if (ret < 0) {
- dev_err(palmas->dev, "POLARITY_CTRL updat failed: %d\n", ret);
+ dev_err(palmas->dev, "POLARITY_CTRL update failed: %d\n", ret);
goto err_i2c;
}
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index 98029ee0959e..850590aac008 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -927,7 +927,7 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
{
- dev_info(&(pcr->pci->dev), "%s: pcr->msi_en = %d, pci->irq = %d\n",
+ pcr_dbg(pcr, "%s: pcr->msi_en = %d, pci->irq = %d\n",
__func__, pcr->msi_en, pcr->pci->irq);
if (request_irq(pcr->pci->irq, rtsx_pci_isr,
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c
index 9292202039ee..3aeafa228baf 100644
--- a/drivers/mfd/sta2x11-mfd.c
+++ b/drivers/mfd/sta2x11-mfd.c
@@ -60,8 +60,8 @@ static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev)
struct sta2x11_mfd *mfd;
if (!pdev && !list_empty(&sta2x11_mfd_list)) {
- pr_warning("%s: Unspecified device, "
- "using first instance\n", __func__);
+ pr_warn("%s: Unspecified device, using first instance\n",
+ __func__);
return list_entry(sta2x11_mfd_list.next,
struct sta2x11_mfd, list);
}
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index 41bd9017f3d0..2182f00db101 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -15,7 +15,7 @@ static const struct regmap_config stm32_timers_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = sizeof(u32),
- .max_register = 0x400,
+ .max_register = 0x3fc,
};
static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
@@ -61,6 +61,13 @@ static int stm32_timers_probe(struct platform_device *pdev)
return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
}
+static int stm32_timers_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+
+ return 0;
+}
+
static const struct of_device_id stm32_timers_of_match[] = {
{ .compatible = "st,stm32-timers", },
{ /* end node */ },
@@ -69,6 +76,7 @@ MODULE_DEVICE_TABLE(of, stm32_timers_of_match);
static struct platform_driver stm32_timers_driver = {
.probe = stm32_timers_probe,
+ .remove = stm32_timers_remove,
.driver = {
.name = "stm32-timers",
.of_match_table = stm32_timers_of_match,
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index b0c7bcdaf5df..566caca4efd8 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -568,6 +568,8 @@ static const u8 stmpe1600_regs[] = {
[STMPE_IDX_GPMR_CSB] = STMPE1600_REG_GPMR_MSB,
[STMPE_IDX_GPSR_LSB] = STMPE1600_REG_GPSR_LSB,
[STMPE_IDX_GPSR_CSB] = STMPE1600_REG_GPSR_MSB,
+ [STMPE_IDX_GPCR_LSB] = STMPE1600_REG_GPSR_LSB,
+ [STMPE_IDX_GPCR_CSB] = STMPE1600_REG_GPSR_MSB,
[STMPE_IDX_GPDR_LSB] = STMPE1600_REG_GPDR_LSB,
[STMPE_IDX_GPDR_CSB] = STMPE1600_REG_GPDR_MSB,
[STMPE_IDX_IEGPIOR_LSB] = STMPE1600_REG_IEGPIOR_LSB,
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 94bd89cb1f06..22c811396edc 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -69,7 +69,7 @@ static const struct resource t7l66xb_mmc_resources[] = {
struct t7l66xb {
void __iomem *scr;
/* Lock to protect registers requiring read/modify/write ops. */
- spinlock_t lock;
+ raw_spinlock_t lock;
struct resource rscr;
struct clk *clk48m;
@@ -89,13 +89,13 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
clk_prepare_enable(t7l66xb->clk32k);
- spin_lock_irqsave(&t7l66xb->lock, flags);
+ raw_spin_lock_irqsave(&t7l66xb->lock, flags);
dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
dev_ctl |= SCR_DEV_CTL_MMC;
tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
- spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
t7l66xb_mmc_resources[0].start & 0xfffe);
@@ -110,13 +110,13 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
unsigned long flags;
u8 dev_ctl;
- spin_lock_irqsave(&t7l66xb->lock, flags);
+ raw_spin_lock_irqsave(&t7l66xb->lock, flags);
dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
dev_ctl &= ~SCR_DEV_CTL_MMC;
tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
- spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
clk_disable_unprepare(t7l66xb->clk32k);
@@ -206,11 +206,11 @@ static void t7l66xb_irq_mask(struct irq_data *data)
unsigned long flags;
u8 imr;
- spin_lock_irqsave(&t7l66xb->lock, flags);
+ raw_spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
imr |= 1 << (data->irq - t7l66xb->irq_base);
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
- spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
static void t7l66xb_irq_unmask(struct irq_data *data)
@@ -219,11 +219,11 @@ static void t7l66xb_irq_unmask(struct irq_data *data)
unsigned long flags;
u8 imr;
- spin_lock_irqsave(&t7l66xb->lock, flags);
+ raw_spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
imr &= ~(1 << (data->irq - t7l66xb->irq_base));
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
- spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
static struct irq_chip t7l66xb_chip = {
@@ -321,7 +321,7 @@ static int t7l66xb_probe(struct platform_device *dev)
if (!t7l66xb)
return -ENOMEM;
- spin_lock_init(&t7l66xb->lock);
+ raw_spin_lock_init(&t7l66xb->lock);
platform_set_drvdata(dev, t7l66xb);
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index d42d322ac7ca..d16e71bd9482 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -95,7 +95,7 @@ struct tc6393xb {
struct clk *clk; /* 3,6 Mhz */
- spinlock_t lock; /* protects RMW cycles */
+ raw_spinlock_t lock; /* protects RMW cycles */
struct {
u8 fer;
@@ -126,13 +126,13 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
/* SMD buffer on */
dev_dbg(&dev->dev, "SMD buffer on\n");
tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1));
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -226,7 +226,7 @@ static int tc6393xb_ohci_enable(struct platform_device *dev)
u16 ccr;
u8 fer;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
ccr |= SCR_CCR_USBCK;
@@ -236,7 +236,7 @@ static int tc6393xb_ohci_enable(struct platform_device *dev)
fer |= SCR_FER_USBEN;
tmio_iowrite8(fer, tc6393xb->scr + SCR_FER);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -248,7 +248,7 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
u16 ccr;
u8 fer;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
fer = tmio_ioread8(tc6393xb->scr + SCR_FER);
fer &= ~SCR_FER_USBEN;
@@ -258,7 +258,7 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
ccr &= ~SCR_CCR_USBCK;
tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -280,14 +280,14 @@ static int tc6393xb_fb_enable(struct platform_device *dev)
unsigned long flags;
u16 ccr;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
ccr &= ~SCR_CCR_MCLK_MASK;
ccr |= SCR_CCR_MCLK_48;
tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -298,14 +298,14 @@ static int tc6393xb_fb_disable(struct platform_device *dev)
unsigned long flags;
u16 ccr;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
ccr &= ~SCR_CCR_MCLK_MASK;
ccr |= SCR_CCR_MCLK_OFF;
tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -317,7 +317,7 @@ int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
u8 fer;
unsigned long flags;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
fer = ioread8(tc6393xb->scr + SCR_FER);
if (on)
@@ -326,7 +326,7 @@ int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
fer &= ~SCR_FER_SLCDEN;
iowrite8(fer, tc6393xb->scr + SCR_FER);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -338,12 +338,12 @@ int tc6393xb_lcd_mode(struct platform_device *fb,
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0);
iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -462,11 +462,11 @@ static void tc6393xb_gpio_set(struct gpio_chip *chip,
struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
unsigned long flags;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
__tc6393xb_gpio_set(chip, offset, value);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
@@ -476,13 +476,13 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
unsigned long flags;
u8 doecr;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
doecr &= ~TC_GPIO_BIT(offset);
tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -494,7 +494,7 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
unsigned long flags;
u8 doecr;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
__tc6393xb_gpio_set(chip, offset, value);
@@ -502,7 +502,7 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
doecr |= TC_GPIO_BIT(offset);
tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
@@ -548,11 +548,11 @@ static void tc6393xb_irq_mask(struct irq_data *data)
unsigned long flags;
u8 imr;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
imr |= 1 << (data->irq - tc6393xb->irq_base);
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static void tc6393xb_irq_unmask(struct irq_data *data)
@@ -561,11 +561,11 @@ static void tc6393xb_irq_unmask(struct irq_data *data)
unsigned long flags;
u8 imr;
- spin_lock_irqsave(&tc6393xb->lock, flags);
+ raw_spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
imr &= ~(1 << (data->irq - tc6393xb->irq_base));
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
- spin_unlock_irqrestore(&tc6393xb->lock, flags);
+ raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static struct irq_chip tc6393xb_chip = {
@@ -628,7 +628,7 @@ static int tc6393xb_probe(struct platform_device *dev)
goto err_kzalloc;
}
- spin_lock_init(&tc6393xb->lock);
+ raw_spin_lock_init(&tc6393xb->lock);
platform_set_drvdata(dev, tc6393xb);
diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c
new file mode 100644
index 000000000000..cfb411cde51c
--- /dev/null
+++ b/drivers/mfd/ti-lmu.c
@@ -0,0 +1,259 @@
+/*
+ * TI LMU (Lighting Management Unit) Core Driver
+ *
+ * Copyright 2017 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.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/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+
+struct ti_lmu_data {
+ struct mfd_cell *cells;
+ int num_cells;
+ unsigned int max_register;
+};
+
+static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id)
+{
+ int ret;
+
+ if (gpio_is_valid(lmu->en_gpio)) {
+ ret = devm_gpio_request_one(lmu->dev, lmu->en_gpio,
+ GPIOF_OUT_INIT_HIGH, "lmu_hwen");
+ if (ret) {
+ dev_err(lmu->dev, "Can not request enable GPIO: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /* Delay about 1ms after HW enable pin control */
+ usleep_range(1000, 1500);
+
+ /* LM3631 has additional power up sequence - enable LCD_EN bit. */
+ if (id == LM3631) {
+ return regmap_update_bits(lmu->regmap, LM3631_REG_DEVCTRL,
+ LM3631_LCD_EN_MASK,
+ LM3631_LCD_EN_MASK);
+ }
+
+ return 0;
+}
+
+static void ti_lmu_disable_hw(struct ti_lmu *lmu)
+{
+ if (gpio_is_valid(lmu->en_gpio))
+ gpio_set_value(lmu->en_gpio, 0);
+}
+
+static struct mfd_cell lm3532_devices[] = {
+ {
+ .name = "ti-lmu-backlight",
+ .id = LM3532,
+ .of_compatible = "ti,lm3532-backlight",
+ },
+};
+
+#define LM363X_REGULATOR(_id) \
+{ \
+ .name = "lm363x-regulator", \
+ .id = _id, \
+ .of_compatible = "ti,lm363x-regulator", \
+} \
+
+static struct mfd_cell lm3631_devices[] = {
+ LM363X_REGULATOR(LM3631_BOOST),
+ LM363X_REGULATOR(LM3631_LDO_CONT),
+ LM363X_REGULATOR(LM3631_LDO_OREF),
+ LM363X_REGULATOR(LM3631_LDO_POS),
+ LM363X_REGULATOR(LM3631_LDO_NEG),
+ {
+ .name = "ti-lmu-backlight",
+ .id = LM3631,
+ .of_compatible = "ti,lm3631-backlight",
+ },
+};
+
+static struct mfd_cell lm3632_devices[] = {
+ LM363X_REGULATOR(LM3632_BOOST),
+ LM363X_REGULATOR(LM3632_LDO_POS),
+ LM363X_REGULATOR(LM3632_LDO_NEG),
+ {
+ .name = "ti-lmu-backlight",
+ .id = LM3632,
+ .of_compatible = "ti,lm3632-backlight",
+ },
+};
+
+static struct mfd_cell lm3633_devices[] = {
+ {
+ .name = "ti-lmu-backlight",
+ .id = LM3633,
+ .of_compatible = "ti,lm3633-backlight",
+ },
+ {
+ .name = "lm3633-leds",
+ .of_compatible = "ti,lm3633-leds",
+ },
+ /* Monitoring driver for open/short circuit detection */
+ {
+ .name = "ti-lmu-fault-monitor",
+ .id = LM3633,
+ .of_compatible = "ti,lm3633-fault-monitor",
+ },
+};
+
+static struct mfd_cell lm3695_devices[] = {
+ {
+ .name = "ti-lmu-backlight",
+ .id = LM3695,
+ .of_compatible = "ti,lm3695-backlight",
+ },
+};
+
+static struct mfd_cell lm3697_devices[] = {
+ {
+ .name = "ti-lmu-backlight",
+ .id = LM3697,
+ .of_compatible = "ti,lm3697-backlight",
+ },
+ /* Monitoring driver for open/short circuit detection */
+ {
+ .name = "ti-lmu-fault-monitor",
+ .id = LM3697,
+ .of_compatible = "ti,lm3697-fault-monitor",
+ },
+};
+
+#define TI_LMU_DATA(chip, max_reg) \
+static const struct ti_lmu_data chip##_data = \
+{ \
+ .cells = chip##_devices, \
+ .num_cells = ARRAY_SIZE(chip##_devices),\
+ .max_register = max_reg, \
+} \
+
+TI_LMU_DATA(lm3532, LM3532_MAX_REG);
+TI_LMU_DATA(lm3631, LM3631_MAX_REG);
+TI_LMU_DATA(lm3632, LM3632_MAX_REG);
+TI_LMU_DATA(lm3633, LM3633_MAX_REG);
+TI_LMU_DATA(lm3695, LM3695_MAX_REG);
+TI_LMU_DATA(lm3697, LM3697_MAX_REG);
+
+static const struct of_device_id ti_lmu_of_match[] = {
+ { .compatible = "ti,lm3532", .data = &lm3532_data },
+ { .compatible = "ti,lm3631", .data = &lm3631_data },
+ { .compatible = "ti,lm3632", .data = &lm3632_data },
+ { .compatible = "ti,lm3633", .data = &lm3633_data },
+ { .compatible = "ti,lm3695", .data = &lm3695_data },
+ { .compatible = "ti,lm3697", .data = &lm3697_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
+
+static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+ struct device *dev = &cl->dev;
+ const struct of_device_id *match;
+ const struct ti_lmu_data *data;
+ struct regmap_config regmap_cfg;
+ struct ti_lmu *lmu;
+ int ret;
+
+ match = of_match_device(ti_lmu_of_match, dev);
+ if (!match)
+ return -ENODEV;
+ /*
+ * Get device specific data from of_match table.
+ * This data is defined by using TI_LMU_DATA() macro.
+ */
+ data = (struct ti_lmu_data *)match->data;
+
+ lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL);
+ if (!lmu)
+ return -ENOMEM;
+
+ lmu->dev = &cl->dev;
+
+ /* Setup regmap */
+ memset(&regmap_cfg, 0, sizeof(struct regmap_config));
+ regmap_cfg.reg_bits = 8;
+ regmap_cfg.val_bits = 8;
+ regmap_cfg.name = id->name;
+ regmap_cfg.max_register = data->max_register;
+
+ lmu->regmap = devm_regmap_init_i2c(cl, &regmap_cfg);
+ if (IS_ERR(lmu->regmap))
+ return PTR_ERR(lmu->regmap);
+
+ /* HW enable pin control and additional power up sequence if required */
+ lmu->en_gpio = of_get_named_gpio(dev->of_node, "enable-gpios", 0);
+ ret = ti_lmu_enable_hw(lmu, id->driver_data);
+ if (ret)
+ return ret;
+
+ /*
+ * Fault circuit(open/short) can be detected by ti-lmu-fault-monitor.
+ * After fault detection is done, some devices should re-initialize
+ * configuration. The notifier enables such kind of handling.
+ */
+ BLOCKING_INIT_NOTIFIER_HEAD(&lmu->notifier);
+
+ i2c_set_clientdata(cl, lmu);
+
+ return mfd_add_devices(lmu->dev, 0, data->cells,
+ data->num_cells, NULL, 0, NULL);
+}
+
+static int ti_lmu_remove(struct i2c_client *cl)
+{
+ struct ti_lmu *lmu = i2c_get_clientdata(cl);
+
+ ti_lmu_disable_hw(lmu);
+ mfd_remove_devices(lmu->dev);
+ return 0;
+}
+
+static const struct i2c_device_id ti_lmu_ids[] = {
+ { "lm3532", LM3532 },
+ { "lm3631", LM3631 },
+ { "lm3632", LM3632 },
+ { "lm3633", LM3633 },
+ { "lm3695", LM3695 },
+ { "lm3697", LM3697 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
+
+static struct i2c_driver ti_lmu_driver = {
+ .probe = ti_lmu_probe,
+ .remove = ti_lmu_remove,
+ .driver = {
+ .name = "ti-lmu",
+ .of_match_table = ti_lmu_of_match,
+ },
+ .id_table = ti_lmu_ids,
+};
+
+module_i2c_driver(ti_lmu_driver);
+
+MODULE_DESCRIPTION("TI LMU MFD Core Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
index 4aeba9b6942a..3bd75061f777 100644
--- a/drivers/mfd/tps65912-spi.c
+++ b/drivers/mfd/tps65912-spi.c
@@ -49,9 +49,9 @@ static int tps65912_spi_probe(struct spi_device *spi)
return tps65912_device_init(tps);
}
-static int tps65912_spi_remove(struct spi_device *client)
+static int tps65912_spi_remove(struct spi_device *spi)
{
- struct tps65912 *tps = spi_get_drvdata(client);
+ struct tps65912 *tps = spi_get_drvdata(spi);
return tps65912_device_exit(tps);
}
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 1beb722f6080..f4b2c29d77e3 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -502,9 +502,7 @@ static int load_twl4030_script(const struct twl4030_power_data *pdata,
}
if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
if (!order)
- pr_warning("TWL4030: Bad order of scripts (sleep "\
- "script before wakeup) Leads to boot"\
- "failure on some boards\n");
+ pr_warn("TWL4030: Bad order of scripts (sleep script before wakeup) Leads to boot failure on some boards\n");
err = twl4030_config_sleep_sequence(address);
}
out:
@@ -701,6 +699,7 @@ static struct twl4030_ins omap3_wrst_seq[] = {
TWL_RESOURCE_RESET(RES_MAIN_REF),
TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2),
TWL_RESOURCE_RESET(RES_VUSB_3V1),
+ TWL_RESOURCE_RESET(RES_VMMC1),
TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1),
TWL_RESOURCE_GROUP_RESET(RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0),
TWL_RESOURCE_ON(RES_RESET),
@@ -929,8 +928,7 @@ static int twl4030_power_probe(struct platform_device *pdev)
err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
if (err) {
- pr_warning("TWL4030 Unable to read registers\n");
-
+ pr_warn("TWL4030 Unable to read registers\n");
} else if (!(val & SEQ_OFFSYNC)) {
val |= SEQ_OFFSYNC;
err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val,
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 3e0e99ec5836..13a4c1190dca 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -19,6 +19,8 @@
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
@@ -1613,12 +1615,24 @@ struct regmap_config wm831x_regmap_config = {
};
EXPORT_SYMBOL_GPL(wm831x_regmap_config);
+const struct of_device_id wm831x_of_match[] = {
+ { .compatible = "wlf,wm8310", .data = (void *)WM8310 },
+ { .compatible = "wlf,wm8311", .data = (void *)WM8311 },
+ { .compatible = "wlf,wm8312", .data = (void *)WM8312 },
+ { .compatible = "wlf,wm8320", .data = (void *)WM8320 },
+ { .compatible = "wlf,wm8321", .data = (void *)WM8321 },
+ { .compatible = "wlf,wm8325", .data = (void *)WM8325 },
+ { .compatible = "wlf,wm8326", .data = (void *)WM8326 },
+ { },
+};
+EXPORT_SYMBOL_GPL(wm831x_of_match);
+
/*
* Instantiate the generic non-control parts of the device.
*/
-int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
+int wm831x_device_init(struct wm831x *wm831x, int irq)
{
- struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
+ struct wm831x_pdata *pdata = &wm831x->pdata;
int rev, wm831x_num;
enum wm831x_parent parent;
int ret, i;
@@ -1627,8 +1641,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
mutex_init(&wm831x->key_lock);
dev_set_drvdata(wm831x->dev, wm831x);
- if (pdata)
- wm831x->soft_shutdown = pdata->soft_shutdown;
+ wm831x->soft_shutdown = pdata->soft_shutdown;
ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
if (ret < 0) {
@@ -1663,7 +1676,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
*/
if (ret == 0) {
dev_info(wm831x->dev, "Device is an engineering sample\n");
- ret = id;
+ ret = wm831x->type;
}
switch (ret) {
@@ -1736,9 +1749,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
/* This will need revisiting in future but is OK for all
* current parts.
*/
- if (parent != id)
- dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
- id);
+ if (parent != wm831x->type)
+ dev_warn(wm831x->dev, "Device was registered as a WM%x\n",
+ wm831x->type);
/* Bootstrap the user key */
ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index 824bcbaa9624..781af060f32d 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -19,6 +19,8 @@
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/mfd/wm831x/core.h>
@@ -27,15 +29,26 @@
static int wm831x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ struct wm831x_pdata *pdata = dev_get_platdata(&i2c->dev);
+ const struct of_device_id *of_id;
struct wm831x *wm831x;
+ enum wm831x_parent type;
int ret;
+ if (i2c->dev.of_node) {
+ of_id = of_match_device(wm831x_of_match, &i2c->dev);
+ type = (enum wm831x_parent)of_id->data;
+ } else {
+ type = (enum wm831x_parent)id->driver_data;
+ }
+
wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c, wm831x);
wm831x->dev = &i2c->dev;
+ wm831x->type = type;
wm831x->regmap = devm_regmap_init_i2c(i2c, &wm831x_regmap_config);
if (IS_ERR(wm831x->regmap)) {
@@ -45,7 +58,10 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
return ret;
}
- return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
+ if (pdata)
+ memcpy(&wm831x->pdata, pdata, sizeof(*pdata));
+
+ return wm831x_device_init(wm831x, i2c->irq);
}
static int wm831x_i2c_remove(struct i2c_client *i2c)
@@ -94,6 +110,7 @@ static struct i2c_driver wm831x_i2c_driver = {
.driver = {
.name = "wm831x",
.pm = &wm831x_pm_ops,
+ .of_match_table = of_match_ptr(wm831x_of_match),
},
.probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove,
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index dfea8b9c2fe6..c01239a600db 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -564,7 +564,7 @@ static const struct irq_domain_ops wm831x_irq_domain_ops = {
int wm831x_irq_init(struct wm831x *wm831x, int irq)
{
- struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
+ struct wm831x_pdata *pdata = &wm831x->pdata;
struct irq_domain *domain;
int i, ret, irq_base;
@@ -579,7 +579,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
}
/* Try to dynamically allocate IRQs if no base is specified */
- if (pdata && pdata->irq_base) {
+ if (pdata->irq_base) {
irq_base = irq_alloc_descs(pdata->irq_base, 0,
WM831X_NUM_IRQS, 0);
if (irq_base < 0) {
@@ -608,7 +608,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
return -EINVAL;
}
- if (pdata && pdata->irq_cmos)
+ if (pdata->irq_cmos)
i = 0;
else
i = WM831X_IRQ_OD;
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 80482aeb246a..c332e2885b26 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -14,6 +14,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
@@ -23,12 +25,19 @@
static int wm831x_spi_probe(struct spi_device *spi)
{
+ struct wm831x_pdata *pdata = dev_get_platdata(&spi->dev);
const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct of_device_id *of_id;
struct wm831x *wm831x;
enum wm831x_parent type;
int ret;
- type = (enum wm831x_parent)id->driver_data;
+ if (spi->dev.of_node) {
+ of_id = of_match_device(wm831x_of_match, &spi->dev);
+ type = (enum wm831x_parent)of_id->data;
+ } else {
+ type = (enum wm831x_parent)id->driver_data;
+ }
wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
@@ -38,6 +47,7 @@ static int wm831x_spi_probe(struct spi_device *spi)
spi_set_drvdata(spi, wm831x);
wm831x->dev = &spi->dev;
+ wm831x->type = type;
wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config);
if (IS_ERR(wm831x->regmap)) {
@@ -47,7 +57,10 @@ static int wm831x_spi_probe(struct spi_device *spi)
return ret;
}
- return wm831x_device_init(wm831x, type, spi->irq);
+ if (pdata)
+ memcpy(&wm831x->pdata, pdata, sizeof(*pdata));
+
+ return wm831x_device_init(wm831x, spi->irq);
}
static int wm831x_spi_remove(struct spi_device *spi)
@@ -97,6 +110,7 @@ static struct spi_driver wm831x_spi_driver = {
.driver = {
.name = "wm831x",
.pm = &wm831x_spi_pm,
+ .of_match_table = of_match_ptr(wm831x_of_match),
},
.id_table = wm831x_spi_ids,
.probe = wm831x_spi_probe,