From 408bc03bb1d5aea34dd444fd6f1f566a5303793d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 15 Jun 2017 20:49:22 +0200 Subject: mfd: retu: Drop -mfd suffix from I2C device ID name It's not correct to encode the subsystem in the I2C device name, so drop the -mfd suffix. To maintain bisect-ability, change driver and platform code / DTS users in the same patch. Suggested-by: Lee Jones Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Acked-by: Aaro Koskinen Acked-by: Tony Lindgren Reviewed-by: Wolfram Sang Signed-off-by: Lee Jones --- drivers/mfd/retu-mfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index d4c114abeb75..53e1d386d2c0 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -302,8 +302,8 @@ static int retu_remove(struct i2c_client *i2c) } static const struct i2c_device_id retu_id[] = { - { "retu-mfd", 0 }, - { "tahvo-mfd", 0 }, + { "retu", 0 }, + { "tahvo", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, retu_id); -- cgit From 46c20bdfd1a47c3ef3c0d31afdc7ac61a16baed1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 15 Jun 2017 20:49:23 +0200 Subject: mfd: retu: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have a OF device ID table if the devices are registered via OF. Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Acked-by: Aaro Koskinen Acked-by: Tony Lindgren Reviewed-by: Wolfram Sang Signed-off-by: Lee Jones --- drivers/mfd/retu-mfd.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index 53e1d386d2c0..e7d27b7861c1 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -308,9 +308,17 @@ static const struct i2c_device_id retu_id[] = { }; MODULE_DEVICE_TABLE(i2c, retu_id); +static const struct of_device_id retu_of_match[] = { + { .compatible = "nokia,retu" }, + { .compatible = "nokia,tahvo" }, + { } +}; +MODULE_DEVICE_TABLE(of, retu_of_match); + static struct i2c_driver retu_driver = { .driver = { .name = "retu-mfd", + .of_match_table = retu_of_match, }, .probe = retu_probe, .remove = retu_remove, -- cgit From 125b249ea57ca908cdffc959f12924b059502c4d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 15 Jun 2017 20:49:27 +0200 Subject: mfd: tps6105x: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have a OF device ID table if the devices are registered via OF. Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Acked-by: Tony Lindgren Signed-off-by: Lee Jones --- drivers/mfd/tps6105x.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index baa12ea666fb..187848c93779 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -173,9 +173,17 @@ static const struct i2c_device_id tps6105x_id[] = { }; MODULE_DEVICE_TABLE(i2c, tps6105x_id); +static const struct of_device_id tps6105x_of_match[] = { + { .compatible = "ti,tps61050" }, + { .compatible = "ti,tps61052" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tps6105x_of_match); + static struct i2c_driver tps6105x_driver = { .driver = { .name = "tps6105x", + .of_match_table = tps6105x_of_match, }, .probe = tps6105x_probe, .remove = tps6105x_remove, -- cgit From 0335a9554b4d6acc2d17efe752bff54ce59b57eb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 14 Aug 2017 18:34:22 +0200 Subject: mfd: dm355evm_msp: Move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Acked-by: Alexandre Belloni Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/mfd/dm355evm_msp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 86eca614507b..2a2756709f22 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* -- cgit From 9787076c43a86f3465d46aa344cc3e2f607ae72f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 14 Aug 2017 18:34:23 +0200 Subject: mfd: tps65010: Move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Acked-by: Greg Kroah-Hartman Acked-by: Krzysztof Kozlowski Acked-by: Bartlomiej Zolnierkiewicz Acked-by: Tony Lindgren Signed-off-by: Lee Jones --- drivers/mfd/tps65010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index d829a6131f09..2ab67386b4ef 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include -- cgit From 9d6105e19f617406aea46dd19281080c7c5ae0d8 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Mon, 21 Aug 2017 03:28:34 +0200 Subject: mfd: rk808: Fix up the chip id get failed the rk8xx chip id is: ((MSB << 8) | LSB) & 0xfff0 Signed-off-by: Elaine Zhang Signed-off-by: Joseph Chen Signed-off-by: Heiko Stuebner Signed-off-by: Lee Jones --- drivers/mfd/rk808.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index fd087cbb0bde..8e60ebaeaadb 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -325,7 +325,7 @@ static int rk808_probe(struct i2c_client *client, void (*pm_pwroff_fn)(void); int nr_pre_init_regs; int nr_cells; - int pm_off = 0; + int pm_off = 0, msb, lsb; int ret; int i; @@ -333,14 +333,23 @@ static int rk808_probe(struct i2c_client *client, if (!rk808) return -ENOMEM; - rk808->variant = i2c_smbus_read_word_data(client, RK808_ID_MSB); - if (rk808->variant < 0) { - dev_err(&client->dev, "Failed to read the chip id at 0x%02x\n", + /* Read chip variant */ + msb = i2c_smbus_read_byte_data(client, RK808_ID_MSB); + if (msb < 0) { + dev_err(&client->dev, "failed to read the chip id at 0x%x\n", RK808_ID_MSB); - return rk808->variant; + return msb; } - dev_dbg(&client->dev, "Chip id: 0x%x\n", (unsigned int)rk808->variant); + lsb = i2c_smbus_read_byte_data(client, RK808_ID_LSB); + if (lsb < 0) { + dev_err(&client->dev, "failed to read the chip id at 0x%x\n", + RK808_ID_LSB); + return lsb; + } + + rk808->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK; + dev_info(&client->dev, "chip id: 0x%x\n", (unsigned int)rk808->variant); switch (rk808->variant) { case RK808_ID: -- cgit From 990f05f6a5213be50ff48bf0461e2db254817b0c Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Mon, 21 Aug 2017 03:28:38 +0200 Subject: mfd: rk808: Add RK805 support The RK805 chip is a Power Management IC (PMIC) for multimedia and handheld devices. It contains the following components: - Regulators - RTC - Clocking Both RK808 and RK805 chips are using a similar register map, so we can reuse the RTC and Clocking functionality. Signed-off-by: Elaine Zhang Signed-off-by: Joseph Chen Signed-off-by: Heiko Stuebner Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 4 +- drivers/mfd/rk808.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 94ad2c1c3d90..38d3ea466f74 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -951,13 +951,13 @@ config MFD_RC5T583 different functionality of the device. config MFD_RK808 - tristate "Rockchip RK808/RK818 Power Management Chip" + tristate "Rockchip RK805/RK808/RK818 Power Management Chip" depends on I2C && OF select MFD_CORE select REGMAP_I2C select REGMAP_IRQ help - If you say yes here you get support for the RK808 and RK818 + If you say yes here you get support for the RK805, RK808 and RK818 Power Management chips. This driver provides common support for accessing the device through I2C interface. The device supports multiple sub-devices diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 8e60ebaeaadb..18329c8b4fe7 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -70,6 +70,14 @@ static const struct regmap_config rk818_regmap_config = { .volatile_reg = rk808_is_volatile_reg, }; +static const struct regmap_config rk805_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK805_OFF_SOURCE_REG, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = rk808_is_volatile_reg, +}; + static const struct regmap_config rk808_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -86,6 +94,16 @@ static struct resource rtc_resources[] = { } }; +static const struct mfd_cell rk805s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), + .resources = &rtc_resources[0], + }, +}; + static const struct mfd_cell rk808s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, @@ -106,6 +124,20 @@ static const struct mfd_cell rk818s[] = { }, }; +static const struct rk808_reg_data rk805_pre_init_reg[] = { + {RK805_BUCK1_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK, + RK805_BUCK1_2_ILMAX_4000MA}, + {RK805_BUCK2_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK, + RK805_BUCK1_2_ILMAX_4000MA}, + {RK805_BUCK3_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK, + RK805_BUCK3_ILMAX_3000MA}, + {RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK, + RK805_BUCK4_ILMAX_3500MA}, + {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA}, + {RK805_GPIO_IO_POL_REG, SLP_SD_MSK, SLEEP_FUN}, + {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C}, +}; + static const struct rk808_reg_data rk808_pre_init_reg[] = { { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA }, { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA }, @@ -135,6 +167,41 @@ static const struct rk808_reg_data rk818_pre_init_reg[] = { VB_LO_SEL_3500MV }, }; +static const struct regmap_irq rk805_irqs[] = { + [RK805_IRQ_PWRON_RISE] = { + .mask = RK805_IRQ_PWRON_RISE_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_VB_LOW] = { + .mask = RK805_IRQ_VB_LOW_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_PWRON] = { + .mask = RK805_IRQ_PWRON_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_PWRON_LP] = { + .mask = RK805_IRQ_PWRON_LP_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_HOTDIE] = { + .mask = RK805_IRQ_HOTDIE_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_RTC_ALARM] = { + .mask = RK805_IRQ_RTC_ALARM_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_RTC_PERIOD] = { + .mask = RK805_IRQ_RTC_PERIOD_MSK, + .reg_offset = 0, + }, + [RK805_IRQ_PWRON_FALL] = { + .mask = RK805_IRQ_PWRON_FALL_MSK, + .reg_offset = 0, + }, +}; + static const struct regmap_irq rk808_irqs[] = { /* INT_STS */ [RK808_IRQ_VOUT_LO] = { @@ -247,6 +314,17 @@ static const struct regmap_irq rk818_irqs[] = { }, }; +static struct regmap_irq_chip rk805_irq_chip = { + .name = "rk805", + .irqs = rk805_irqs, + .num_irqs = ARRAY_SIZE(rk805_irqs), + .num_regs = 1, + .status_base = RK805_INT_STS_REG, + .mask_base = RK805_INT_STS_MSK_REG, + .ack_base = RK805_INT_STS_REG, + .init_ack_masked = true, +}; + static const struct regmap_irq_chip rk808_irq_chip = { .name = "rk808", .irqs = rk808_irqs, @@ -272,6 +350,25 @@ static const struct regmap_irq_chip rk818_irq_chip = { }; static struct i2c_client *rk808_i2c_client; + +static void rk805_device_shutdown(void) +{ + int ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + if (!rk808) { + dev_warn(&rk808_i2c_client->dev, + "have no rk805, so do nothing here\n"); + return; + } + + ret = regmap_update_bits(rk808->regmap, + RK805_DEV_CTRL_REG, + DEV_OFF, DEV_OFF); + if (ret) + dev_err(&rk808_i2c_client->dev, "power off error!\n"); +} + static void rk808_device_shutdown(void) { int ret; @@ -309,6 +406,7 @@ static void rk818_device_shutdown(void) } static const struct of_device_id rk808_of_match[] = { + { .compatible = "rockchip,rk805" }, { .compatible = "rockchip,rk808" }, { .compatible = "rockchip,rk818" }, { }, @@ -352,6 +450,15 @@ static int rk808_probe(struct i2c_client *client, dev_info(&client->dev, "chip id: 0x%x\n", (unsigned int)rk808->variant); switch (rk808->variant) { + case RK805_ID: + rk808->regmap_cfg = &rk805_regmap_config; + rk808->regmap_irq_chip = &rk805_irq_chip; + pre_init_reg = rk805_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg); + cells = rk805s; + nr_cells = ARRAY_SIZE(rk805s); + pm_pwroff_fn = rk805_device_shutdown; + break; case RK808_ID: rk808->regmap_cfg = &rk808_regmap_config; rk808->regmap_irq_chip = &rk808_irq_chip; @@ -444,6 +551,7 @@ static int rk808_remove(struct i2c_client *client) } static const struct i2c_device_id rk808_ids[] = { + { "rk805" }, { "rk808" }, { "rk818" }, { }, -- cgit From 8d249b67c785d48c5aa526b47495f7c88a62f73e Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Mon, 21 Aug 2017 03:28:41 +0200 Subject: mfd: rk808: Add RK805 pinctrl support Signed-off-by: Joseph Chen Acked-by: Linus Walleij Signed-off-by: Heiko Stuebner Signed-off-by: Lee Jones --- drivers/mfd/rk808.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 18329c8b4fe7..c803d2d5dfb7 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -97,6 +97,7 @@ static struct resource rtc_resources[] = { static const struct mfd_cell rk805s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, + { .name = "rk805-pinctrl", }, { .name = "rk808-rtc", .num_resources = ARRAY_SIZE(rtc_resources), -- cgit From f7c22398f5e95c995a34d4f196d53cfc32562aed Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Mon, 21 Aug 2017 03:28:42 +0200 Subject: mfd: rk808: Add RK805 power key support Signed-off-by: Joseph Chen Signed-off-by: Heiko Stuebner Signed-off-by: Lee Jones --- drivers/mfd/rk808.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index c803d2d5dfb7..216fbf6adec9 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -94,6 +94,19 @@ static struct resource rtc_resources[] = { } }; +static struct resource rk805_key_resources[] = { + { + .start = RK805_IRQ_PWRON_FALL, + .end = RK805_IRQ_PWRON_FALL, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK805_IRQ_PWRON_RISE, + .end = RK805_IRQ_PWRON_RISE, + .flags = IORESOURCE_IRQ, + } +}; + static const struct mfd_cell rk805s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, @@ -103,6 +116,10 @@ static const struct mfd_cell rk805s[] = { .num_resources = ARRAY_SIZE(rtc_resources), .resources = &rtc_resources[0], }, + { .name = "rk805-pwrkey", + .num_resources = ARRAY_SIZE(rk805_key_resources), + .resources = &rk805_key_resources[0], + }, }; static const struct mfd_cell rk808s[] = { -- cgit From a205425658dead19bb1b8ac00584aed98e60dde2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 14 Aug 2017 18:34:24 +0200 Subject: mfd: twl: Move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Acked-by: Greg Kroah-Hartman Acked-by: Alexandre Belloni Acked-by: Mark Brown Acked-by: Sebastian Reichel Acked-by: Jonathan Cameron Acked-by: Dmitry Torokhov Acked-by: Kishon Vijay Abraham I Acked-by: Bartlomiej Zolnierkiewicz Acked-by: Thierry Reding Acked-by: Tony Lindgren Acked-by: Daniel Thompson Acked-by: Linus Walleij Acked-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/mfd/twl-core.c | 6 +++--- drivers/mfd/twl4030-audio.c | 2 +- drivers/mfd/twl4030-irq.c | 2 +- drivers/mfd/twl4030-power.c | 2 +- drivers/mfd/twl6030-irq.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index c64615dca2bd..2a09dde4ca6e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -44,7 +44,7 @@ #include #include -#include +#include /* Register descriptions for audio */ #include @@ -173,7 +173,7 @@ static struct twl_private *twl_priv; static struct twl_mapping twl4030_map[] = { /* * NOTE: don't change this table without updating the - * defines for TWL4030_MODULE_* + * defines for TWL4030_MODULE_* * so they continue to match the order in this table. */ @@ -344,7 +344,7 @@ static const struct regmap_config twl4030_regmap_config[4] = { static struct twl_mapping twl6030_map[] = { /* * NOTE: don't change this table without updating the - * defines for TWL4030_MODULE_* + * defines for TWL4030_MODULE_* * so they continue to match the order in this table. */ diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 0a1606480023..da16bf45fab4 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 378c02d43bf7..b16c16f194fd 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "twl-core.h" diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index f4b2c29d77e3..6b36932263ba 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 53574508a613..e3ec8dfa9f1e 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From e8924005b4e7964313536547d4b73406330be26d Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 28 Aug 2017 12:04:07 +0200 Subject: mfd: Add STM32 LPTimer driver STM32 Low-Power Timer hardware block can be used for: - PWM generation - IIO trigger (in sync with PWM) - IIO quadrature encoder counter PWM and IIO timer configuration are mixed in the same registers so we need a multi fonction driver to be able to share those registers. Signed-off-by: Fabrice Gasnier Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 14 ++++++ drivers/mfd/Makefile | 1 + drivers/mfd/stm32-lptimer.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 drivers/mfd/stm32-lptimer.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 94ad2c1c3d90..fe76db945f46 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1723,6 +1723,20 @@ config MFD_STW481X in various ST Microelectronics and ST-Ericsson embedded Nomadik series. +config MFD_STM32_LPTIMER + tristate "Support for STM32 Low-Power Timer" + depends on (ARCH_STM32 && OF) || COMPILE_TEST + select MFD_CORE + select REGMAP + select REGMAP_MMIO + help + Select this option to enable STM32 Low-Power Timer driver + used for PWM, IIO Trigger, IIO Encoder and Counter. Shared + resources are also dealt with here. + + To compile this driver as a module, choose M here: the + module will be called stm32-lptimer. + config MFD_STM32_TIMERS tristate "Support for STM32 Timers" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 080793b3fd0e..b80b1a314ca5 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -221,5 +221,6 @@ 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_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c new file mode 100644 index 000000000000..075330a25f61 --- /dev/null +++ b/drivers/mfd/stm32-lptimer.c @@ -0,0 +1,107 @@ +/* + * STM32 Low-Power Timer parent driver. + * + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier + * + * Inspired by Benjamin Gaignard's stm32-timers driver + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include + +#define STM32_LPTIM_MAX_REGISTER 0x3fc + +static const struct regmap_config stm32_lptimer_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = STM32_LPTIM_MAX_REGISTER, +}; + +static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata) +{ + u32 val; + int ret; + + /* + * Quadrature encoder mode bit can only be written and read back when + * Low-Power Timer supports it. + */ + ret = regmap_update_bits(ddata->regmap, STM32_LPTIM_CFGR, + STM32_LPTIM_ENC, STM32_LPTIM_ENC); + if (ret) + return ret; + + ret = regmap_read(ddata->regmap, STM32_LPTIM_CFGR, &val); + if (ret) + return ret; + + ret = regmap_update_bits(ddata->regmap, STM32_LPTIM_CFGR, + STM32_LPTIM_ENC, 0); + if (ret) + return ret; + + ddata->has_encoder = !!(val & STM32_LPTIM_ENC); + + return 0; +} + +static int stm32_lptimer_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stm32_lptimer *ddata; + struct resource *res; + void __iomem *mmio; + int ret; + + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + + ddata->regmap = devm_regmap_init_mmio_clk(dev, "mux", mmio, + &stm32_lptimer_regmap_cfg); + if (IS_ERR(ddata->regmap)) + return PTR_ERR(ddata->regmap); + + ddata->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ddata->clk)) + return PTR_ERR(ddata->clk); + + ret = stm32_lptimer_detect_encoder(ddata); + if (ret) + return ret; + + platform_set_drvdata(pdev, ddata); + + return devm_of_platform_populate(&pdev->dev); +} + +static const struct of_device_id stm32_lptimer_of_match[] = { + { .compatible = "st,stm32-lptimer", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_lptimer_of_match); + +static struct platform_driver stm32_lptimer_driver = { + .probe = stm32_lptimer_probe, + .driver = { + .name = "stm32-lptimer", + .of_match_table = stm32_lptimer_of_match, + }, +}; +module_platform_driver(stm32_lptimer_driver); + +MODULE_AUTHOR("Fabrice Gasnier "); +MODULE_DESCRIPTION("STMicroelectronics STM32 Low-Power Timer"); +MODULE_ALIAS("platform:stm32-lptimer"); +MODULE_LICENSE("GPL v2"); -- cgit From ff827cf5698b111b2e5f825cb9ee508115f94e8a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 30 Jun 2017 11:02:21 +0300 Subject: mfd: twl-core: Improve the documentation Saying it "returns the result" seems tautological. The read function does not return num_bytes on success, it returns zero on success. I noticed this discrepancy because some of the callers were checking for >= 0. Signed-off-by: Dan Carpenter Signed-off-by: Lee Jones --- drivers/mfd/twl-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 2a09dde4ca6e..d3133a371e27 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -448,7 +448,7 @@ static struct regmap *twl_get_regmap(u8 mod_no) * @reg: register address (just offset will do) * @num_bytes: number of bytes to transfer * - * Returns the result of operation - 0 is success + * Returns 0 on success or else a negative error code. */ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) { @@ -476,7 +476,7 @@ EXPORT_SYMBOL(twl_i2c_write); * @reg: register address (just offset will do) * @num_bytes: number of bytes to transfer * - * Returns result of operation - num_bytes is success else failure. + * Returns 0 on success or else a negative error code. */ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) { -- cgit From e26ae3660b9ca2d180131670ae5388580dcf19b3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 30 Jun 2017 10:33:27 +0100 Subject: mfd: rtsx: Make arrays depth and cd_mask static const Don't populate the arrays depath and cd_mask on the stack but make them static const. Makes the object code smaller: text data bss dec hex filename 25413 7216 448 33077 8135 drivers/mfd/rtsx_pcr.o text data bss dec hex filename 25151 7360 448 32959 80bf drivers/mfd/rtsx_pcr.o Signed-off-by: Colin Ian King Signed-off-by: Lee Jones --- drivers/mfd/rtsx_pcr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index a0ac89dfdf0f..3cf69e5c5703 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -644,7 +644,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, { int err, clk; u8 n, clk_divider, mcu_cnt, div; - u8 depth[] = { + static const u8 depth[] = { [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, @@ -768,7 +768,7 @@ EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card) { - unsigned int cd_mask[] = { + static const unsigned int cd_mask[] = { [RTSX_SD_CARD] = SD_EXIST, [RTSX_MS_CARD] = MS_EXIST }; -- cgit From 45f80a9f78f1bcf87c09ae120a68011efe35128a Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 30 Jun 2017 16:35:03 +0200 Subject: mfd: da9052: Fix manual ADC read after timed out read It is possible that under heavy system load, the counter in the completion struct, used for waiting for end of AD conversion, gets incremented twice. To make sure the driver recovers from this situation, the completion struct should be reinitialized. Signed-off-by: Sebastian Reichel Signed-off-by: Lee Jones --- drivers/mfd/da9052-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index a23a3a1c7061..433add43a0a9 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -387,6 +387,8 @@ int da9052_adc_manual_read(struct da9052 *da9052, unsigned char channel) mutex_lock(&da9052->auxadc_lock); + reinit_completion(&da9052->done); + /* Channel gets activated on enabling the Conversion bit */ mux_sel = chan_mux[channel] | DA9052_ADC_MAN_MAN_CONV; -- cgit From 0953075112d7626474b0bb88690f5f1ab93ec803 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 4 May 2017 22:10:54 +0200 Subject: mfd: max8925-i2c: Drop unnecessary static Drop static on a local variable, when the variable is initialized before any use, on every possible execution path through the function. The static has no benefit, and dropping it reduces the code size. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @bad exists@ position p; identifier x; type T; @@ static T x@p; ... x = <+...x...+> @@ identifier x; expression e; type T; position p != bad.p; @@ -static T x@p; ... when != x when strict ?x = e; // The change in code size is indicates by the following output from the size command. before: text data bss dec hex filename 2579 240 16 2835 b13 drivers/mfd/max8925-i2c.o after: text data bss dec hex filename 2531 240 8 2779 adb drivers/mfd/max8925-i2c.o Signed-off-by: Julia Lawall Acked-by: Kees Cook Signed-off-by: Lee Jones --- drivers/mfd/max8925-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 5c80aea3211f..10063236132c 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -151,7 +151,7 @@ static int max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8925_platform_data *pdata = dev_get_platdata(&client->dev); - static struct max8925_chip *chip; + struct max8925_chip *chip; struct device_node *node = client->dev.of_node; if (node && !pdata) { -- cgit From 2042f3c29f2f11129434de8a610878e8a15b4174 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 5 Jul 2017 07:50:54 +0200 Subject: mfd: max8998: Fix potential NULL pointer dereference if 'max8998_i2c_parse_dt_pdata() fails (when out of memory), a NULL pointer dereference will occur in the error handling code. Return directly instead. Fixes: ee999fb3f17f("mfd: max8998: Add support for Device Tree") Signed-off-by: Christophe JAILLET Signed-off-by: Lee Jones --- drivers/mfd/max8998.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 4c33b8063bc3..b1d3f70782d9 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -192,10 +192,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) { pdata = max8998_i2c_parse_dt_pdata(&i2c->dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto err; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } i2c_set_clientdata(i2c, max8998); -- cgit From 52557dc624df7de5808c5c26476f3a8863bb0128 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 10 Jul 2017 11:07:22 +0530 Subject: mfd: ab8500-core: Constify attribute_group structures attribute_groups are not supposed to change at runtime. All functions working with attribute_groups provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 16298 1009 184 17491 4453 drivers/mfd/ab8500-core.o File size After adding 'const': text data bss dec hex filename 16490 817 184 17491 4453 drivers/mfd/ab8500-core.o Signed-off-by: Arvind Yadav Signed-off-by: Lee Jones --- drivers/mfd/ab8500-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 8511c068a610..30d09d177171 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1059,15 +1059,15 @@ static struct attribute *ab9540_sysfs_entries[] = { NULL, }; -static struct attribute_group ab8500_attr_group = { +static const struct attribute_group ab8500_attr_group = { .attrs = ab8500_sysfs_entries, }; -static struct attribute_group ab8505_attr_group = { +static const struct attribute_group ab8505_attr_group = { .attrs = ab8505_sysfs_entries, }; -static struct attribute_group ab9540_attr_group = { +static const struct attribute_group ab9540_attr_group = { .attrs = ab9540_sysfs_entries, }; -- cgit From 5c8f124893c4a691bdae5e9258cb0bca44653f08 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 17 Jul 2017 11:28:55 +0200 Subject: mfd: Kconfig: Add missing Kconfig dependency for TPS65086 MTF_CORE should be enabled when driver is enabled. Without this patch you can configure: CONFIG_MFD_CORE is not set CONFIG_MFD_TPS65086=y ... which ends up with compilation error: drivers/mfd/tps65086.o: In function `tps65086_probe': drivers/mfd/tps65086.c:110: undefined reference to `mfd_add_devices' drivers/mfd/tps65086.c:110:(.text+0x128): relocation truncated to fit: \ R_AARCH64_CALL26 against undefined symbol `mfd_add_devices' Signed-off-by: Michal Simek Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 7a01e70ac0ab..42fb90ae3345 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1294,6 +1294,7 @@ config TPS6507X config MFD_TPS65086 tristate "TI TPS65086 Power Management Integrated Chips (PMICs)" + select MFD_CORE select REGMAP select REGMAP_IRQ select REGMAP_I2C -- cgit From 876368c3caa59b174d9a6ac28b7e88a9a9544eac Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Thu, 20 Jul 2017 15:32:40 +0800 Subject: mfd: hi6421-pmic: Change license text to shorter form Change license text to a shorter form of GPLv2. Signed-off-by: Guodong Xu Acked-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/hi6421-pmic-core.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index 3fd703fe3aba..ad9e3d897085 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -9,17 +9,8 @@ * Author: Guodong Xu * * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include -- cgit From 568e5476cf2b8dfdcf123a67b88fb724beb5487c Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Thu, 20 Jul 2017 15:32:41 +0800 Subject: mfd: hi6421-pmic: Update dev_err messages Update dev_err messages to make them more readable. Signed-off-by: Guodong Xu Acked-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/hi6421-pmic-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index ad9e3d897085..b1139d4b0048 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -52,8 +52,8 @@ static int hi6421_pmic_probe(struct platform_device *pdev) pmic->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, &hi6421_regmap_config); if (IS_ERR(pmic->regmap)) { - dev_err(&pdev->dev, - "regmap init failed: %ld\n", PTR_ERR(pmic->regmap)); + dev_err(&pdev->dev, "Failed to initialise Regmap: %ld\n", + PTR_ERR(pmic->regmap)); return PTR_ERR(pmic->regmap); } @@ -70,7 +70,7 @@ static int hi6421_pmic_probe(struct platform_device *pdev) ret = devm_mfd_add_devices(&pdev->dev, 0, hi6421_devs, ARRAY_SIZE(hi6421_devs), NULL, 0, NULL); if (ret) { - dev_err(&pdev->dev, "add mfd devices failed: %d\n", ret); + dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret); return ret; } -- cgit From ec58871fb9c50429d6b5570066a7166da8faf086 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Thu, 20 Jul 2017 15:32:42 +0800 Subject: mfd: hi6421-pmic: Add support for HiSilicon Hi6421v530 Add support for HiSilicon Hi6421v530 PMIC. Hi6421v530 communicates with main SoC via memory-mapped I/O. Hi6421v530 and Hi6421 are PMIC chips from the same vendor, HiSilicon, but at different revisions. They share the same memory-mapped I/O design. They differ in integrated devices, such as regulator details, LDO voltage points. Signed-off-by: Guodong Xu Signed-off-by: Wang Xiaoyin Acked-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/hi6421-pmic-core.c | 70 +++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 18 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index b1139d4b0048..6fb7ba272e09 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -1,9 +1,9 @@ /* - * Device driver for Hi6421 IC + * Device driver for Hi6421 PMIC * * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. * http://www.hisilicon.com - * Copyright (c) <2013-2014> Linaro Ltd. + * Copyright (c) <2013-2017> Linaro Ltd. * http://www.linaro.org * * Author: Guodong Xu @@ -16,16 +16,20 @@ #include #include #include +#include #include -#include +#include #include #include -#include static const struct mfd_cell hi6421_devs[] = { { .name = "hi6421-regulator", }, }; +static const struct mfd_cell hi6421v530_devs[] = { + { .name = "hi6421v530-regulator", }, +}; + static const struct regmap_config hi6421_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -33,12 +37,33 @@ static const struct regmap_config hi6421_regmap_config = { .max_register = HI6421_REG_TO_BUS_ADDR(HI6421_REG_MAX), }; +static const struct of_device_id of_hi6421_pmic_match[] = { + { + .compatible = "hisilicon,hi6421-pmic", + .data = (void *)HI6421 + }, + { + .compatible = "hisilicon,hi6421v530-pmic", + .data = (void *)HI6421_V530 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match); + static int hi6421_pmic_probe(struct platform_device *pdev) { struct hi6421_pmic *pmic; struct resource *res; + const struct of_device_id *id; + const struct mfd_cell *subdevs; + enum hi6421_type type; void __iomem *base; - int ret; + int n_subdevs, ret; + + id = of_match_device(of_hi6421_pmic_match, &pdev->dev); + if (!id) + return -EINVAL; + type = (enum hi6421_type)id->data; pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) @@ -57,18 +82,33 @@ static int hi6421_pmic_probe(struct platform_device *pdev) return PTR_ERR(pmic->regmap); } - /* set over-current protection debounce 8ms */ - regmap_update_bits(pmic->regmap, HI6421_OCP_DEB_CTRL_REG, + platform_set_drvdata(pdev, pmic); + + switch (type) { + case HI6421: + /* set over-current protection debounce 8ms */ + regmap_update_bits(pmic->regmap, HI6421_OCP_DEB_CTRL_REG, (HI6421_OCP_DEB_SEL_MASK | HI6421_OCP_EN_DEBOUNCE_MASK | HI6421_OCP_AUTO_STOP_MASK), (HI6421_OCP_DEB_SEL_8MS | HI6421_OCP_EN_DEBOUNCE_ENABLE)); - platform_set_drvdata(pdev, pmic); + subdevs = hi6421_devs; + n_subdevs = ARRAY_SIZE(hi6421_devs); + break; + case HI6421_V530: + subdevs = hi6421v530_devs; + n_subdevs = ARRAY_SIZE(hi6421v530_devs); + break; + default: + dev_err(&pdev->dev, "Unknown device type %d\n", + (unsigned int)type); + return -EINVAL; + } - ret = devm_mfd_add_devices(&pdev->dev, 0, hi6421_devs, - ARRAY_SIZE(hi6421_devs), NULL, 0, NULL); + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, + subdevs, n_subdevs, NULL, 0, NULL); if (ret) { dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret); return ret; @@ -77,16 +117,10 @@ static int hi6421_pmic_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id of_hi6421_pmic_match_tbl[] = { - { .compatible = "hisilicon,hi6421-pmic", }, - { }, -}; -MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match_tbl); - static struct platform_driver hi6421_pmic_driver = { .driver = { - .name = "hi6421_pmic", - .of_match_table = of_hi6421_pmic_match_tbl, + .name = "hi6421_pmic", + .of_match_table = of_hi6421_pmic_match, }, .probe = hi6421_pmic_probe, }; -- cgit From d3ea212720948acff862b4c842d5b464ad338841 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 17 Jul 2017 22:45:12 +0200 Subject: mfd: Add ROHM BD9571MWV-M MFD PMIC driver Add the MFD part of the ROHM BD9571MWV-M PMIC driver and MAINTAINERS entry. The MFD part only specifies the regmap bits for the PMIC and binds the subdevs together. Signed-off-by: Marek Vasut Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 14 +++ drivers/mfd/Makefile | 1 + drivers/mfd/bd9571mwv.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 drivers/mfd/bd9571mwv.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 42fb90ae3345..79e4ec6f19a8 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -133,6 +133,20 @@ config MFD_BCM590XX help Support for the BCM590xx PMUs from Broadcom +config MFD_BD9571MWV + tristate "ROHM BD9571MWV PMIC" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C + help + Support for the ROHM BD9571MWV PMIC, which contains single + voltage regulator, voltage sampling units, GPIO block and + watchdog block. + + This driver can also be built as a module. If so, the module + will be called bd9571mwv. + config MFD_AC100 tristate "X-Powers AC100" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b80b1a314ca5..21e19a5f3f3c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -10,6 +10,7 @@ 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_BD9571MWV) += bd9571mwv.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 diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c new file mode 100644 index 000000000000..64e088dfe7b0 --- /dev/null +++ b/drivers/mfd/bd9571mwv.c @@ -0,0 +1,230 @@ +/* + * ROHM BD9571MWV-M MFD driver + * + * Copyright (C) 2017 Marek Vasut + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + * + * Based on the TPS65086 driver + */ + +#include +#include +#include +#include + +#include + +static const struct mfd_cell bd9571mwv_cells[] = { + { .name = "bd9571mwv-regulator", }, + { .name = "bd9571mwv-gpio", }, +}; + +static const struct regmap_range bd9571mwv_readable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION), + regmap_reg_range(BD9571MWV_AVS_SET_MONI, BD9571MWV_AVS_DVFS_VID(3)), + regmap_reg_range(BD9571MWV_VD18_VID, BD9571MWV_VD33_VID), + regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_VINIT), + regmap_reg_range(BD9571MWV_DVFS_SETVMAX, BD9571MWV_DVFS_MONIVDAC), + regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), + regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), +}; + +static const struct regmap_access_table bd9571mwv_readable_table = { + .yes_ranges = bd9571mwv_readable_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9571mwv_readable_yes_ranges), +}; + +static const struct regmap_range bd9571mwv_writable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_AVS_VD09_VID(0), BD9571MWV_AVS_VD09_VID(3)), + regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID), + regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT), + regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), +}; + +static const struct regmap_access_table bd9571mwv_writable_table = { + .yes_ranges = bd9571mwv_writable_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9571mwv_writable_yes_ranges), +}; + +static const struct regmap_range bd9571mwv_volatile_yes_ranges[] = { + regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), + regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ), +}; + +static const struct regmap_access_table bd9571mwv_volatile_table = { + .yes_ranges = bd9571mwv_volatile_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9571mwv_volatile_yes_ranges), +}; + +static const struct regmap_config bd9571mwv_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .rd_table = &bd9571mwv_readable_table, + .wr_table = &bd9571mwv_writable_table, + .volatile_table = &bd9571mwv_volatile_table, + .max_register = 0xff, +}; + +static const struct regmap_irq bd9571mwv_irqs[] = { + REGMAP_IRQ_REG(BD9571MWV_IRQ_MD1, 0, + BD9571MWV_INT_INTREQ_MD1_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E1, 0, + BD9571MWV_INT_INTREQ_MD2_E1_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_MD2_E2, 0, + BD9571MWV_INT_INTREQ_MD2_E2_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_PROT_ERR, 0, + BD9571MWV_INT_INTREQ_PROT_ERR_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_GP, 0, + BD9571MWV_INT_INTREQ_GP_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_128H_OF, 0, + BD9571MWV_INT_INTREQ_128H_OF_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_WDT_OF, 0, + BD9571MWV_INT_INTREQ_WDT_OF_INT), + REGMAP_IRQ_REG(BD9571MWV_IRQ_BKUP_TRG, 0, + BD9571MWV_INT_INTREQ_BKUP_TRG_INT), +}; + +static struct regmap_irq_chip bd9571mwv_irq_chip = { + .name = "bd9571mwv", + .status_base = BD9571MWV_INT_INTREQ, + .mask_base = BD9571MWV_INT_INTMASK, + .ack_base = BD9571MWV_INT_INTREQ, + .init_ack_masked = true, + .num_regs = 1, + .irqs = bd9571mwv_irqs, + .num_irqs = ARRAY_SIZE(bd9571mwv_irqs), +}; + +static int bd9571mwv_identify(struct bd9571mwv *bd) +{ + struct device *dev = bd->dev; + unsigned int value; + int ret; + + ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value); + if (ret) { + dev_err(dev, "Failed to read vendor code register (ret=%i)\n", + ret); + return ret; + } + + if (value != BD9571MWV_VENDOR_CODE_VAL) { + dev_err(dev, "Invalid vendor code ID %02x (expected %02x)\n", + value, BD9571MWV_VENDOR_CODE_VAL); + return -EINVAL; + } + + ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value); + if (ret) { + dev_err(dev, "Failed to read product code register (ret=%i)\n", + ret); + return ret; + } + + if (value != BD9571MWV_PRODUCT_CODE_VAL) { + dev_err(dev, "Invalid product code ID %02x (expected %02x)\n", + value, BD9571MWV_PRODUCT_CODE_VAL); + return -EINVAL; + } + + ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value); + if (ret) { + dev_err(dev, "Failed to read revision register (ret=%i)\n", + ret); + return ret; + } + + dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff); + + return 0; +} + +static int bd9571mwv_probe(struct i2c_client *client, + const struct i2c_device_id *ids) +{ + struct bd9571mwv *bd; + int ret; + + bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL); + if (!bd) + return -ENOMEM; + + i2c_set_clientdata(client, bd); + bd->dev = &client->dev; + bd->irq = client->irq; + + bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config); + if (IS_ERR(bd->regmap)) { + dev_err(bd->dev, "Failed to initialize register map\n"); + return PTR_ERR(bd->regmap); + } + + ret = bd9571mwv_identify(bd); + if (ret) + return ret; + + ret = regmap_add_irq_chip(bd->regmap, bd->irq, IRQF_ONESHOT, 0, + &bd9571mwv_irq_chip, &bd->irq_data); + if (ret) { + dev_err(bd->dev, "Failed to register IRQ chip\n"); + return ret; + } + + ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells, + ARRAY_SIZE(bd9571mwv_cells), NULL, 0, + regmap_irq_get_domain(bd->irq_data)); + if (ret) { + regmap_del_irq_chip(bd->irq, bd->irq_data); + return ret; + } + + return 0; +} + +static int bd9571mwv_remove(struct i2c_client *client) +{ + struct bd9571mwv *bd = i2c_get_clientdata(client); + + regmap_del_irq_chip(bd->irq, bd->irq_data); + + return 0; +} + +static const struct of_device_id bd9571mwv_of_match_table[] = { + { .compatible = "rohm,bd9571mwv", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table); + +static const struct i2c_device_id bd9571mwv_id_table[] = { + { "bd9571mwv", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table); + +static struct i2c_driver bd9571mwv_driver = { + .driver = { + .name = "bd9571mwv", + .of_match_table = bd9571mwv_of_match_table, + }, + .probe = bd9571mwv_probe, + .remove = bd9571mwv_remove, + .id_table = bd9571mwv_id_table, +}; +module_i2c_driver(bd9571mwv_driver); + +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("BD9571MWV PMIC Driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 7303733a6ca2a68b210ebdc09cace8b0ffe8b179 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 26 Jul 2017 16:28:26 +0800 Subject: mfd: axp20x: Add support for AXP813 PMIC The X-Powers AXP813 PMIC is normally used with Allwinner's A83T SoC. It has the same range of functions as other X-Powers PMICs, such as DC-DC buck converter and linear regulator outputs, AC-IN and VBUS power supplies, power button trigger, GPIOs, ADCs, and a battery charger. Note that the IRQ table given in the datasheet is incorrect: in IRQ enable/status registers 1, there are separate IRQs for ACIN and VBUS, instead of bits [7:5] being the same as bits [4:2]. So it shares the same IRQs as the AXP803, rather than the AXP288. This patch adds basic mfd support for it, with only the power button enabled. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Lee Jones --- drivers/mfd/axp20x-rsb.c | 1 + drivers/mfd/axp20x.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c index fd5c7267b136..7ddbd9e8dd03 100644 --- a/drivers/mfd/axp20x-rsb.c +++ b/drivers/mfd/axp20x-rsb.c @@ -64,6 +64,7 @@ static const struct of_device_id axp20x_rsb_of_match[] = { { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, { .compatible = "x-powers,axp809", .data = (void *)AXP809_ID }, + { .compatible = "x-powers,axp813", .data = (void *)AXP813_ID }, { }, }; MODULE_DEVICE_TABLE(of, axp20x_rsb_of_match); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 917b6ddc4f15..ec4271ca065c 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -44,6 +44,7 @@ static const char * const axp20x_model_names[] = { "AXP803", "AXP806", "AXP809", + "AXP813", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -870,6 +871,14 @@ static struct mfd_cell axp809_cells[] = { }, }; +static struct mfd_cell axp813_cells[] = { + { + .name = "axp20x-pek", + .num_resources = ARRAY_SIZE(axp803_pek_resources), + .resources = axp803_pek_resources, + } +}; + static struct axp20x_dev *axp20x_pm_power_off; static void axp20x_power_off(void) { @@ -956,6 +965,19 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_cfg = &axp22x_regmap_config; axp20x->regmap_irq_chip = &axp809_regmap_irq_chip; break; + case AXP813_ID: + axp20x->nr_cells = ARRAY_SIZE(axp813_cells); + axp20x->cells = axp813_cells; + axp20x->regmap_cfg = &axp288_regmap_config; + /* + * The IRQ table given in the datasheet is incorrect. + * In IRQ enable/status registers 1, there are separate + * IRQs for ACIN and VBUS, instead of bits [7:5] being + * the same as bits [4:2]. So it shares the same IRQs + * as the AXP803, rather than the AXP288. + */ + axp20x->regmap_irq_chip = &axp803_regmap_irq_chip; + break; default: dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); return -EINVAL; -- cgit From f446363374e4c31fecad2cf95d877b4631de9890 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 26 Jul 2017 16:28:27 +0800 Subject: mfd: axp20x: Use correct platform device ID for many PEK According to their datasheets, the AXP221, AXP223, AXP288, AXP803, AXP809 and AXP813 PEK have different values for startup time bits from the AXP20X, let's use the platform device id with the correct values. Signed-off-by: Quentin Schulz Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index ec4271ca065c..336de66ca408 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -677,7 +677,7 @@ static struct mfd_cell axp20x_cells[] = { static struct mfd_cell axp221_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, }, { @@ -702,7 +702,7 @@ static struct mfd_cell axp221_cells[] = { static struct mfd_cell axp223_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, }, { @@ -835,7 +835,7 @@ static struct mfd_cell axp288_cells[] = { .resources = axp288_fuel_gauge_resources, }, { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp288_power_button_resources), .resources = axp288_power_button_resources, }, @@ -846,7 +846,7 @@ static struct mfd_cell axp288_cells[] = { static struct mfd_cell axp803_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), .resources = axp803_pek_resources, }, @@ -862,7 +862,7 @@ static struct mfd_cell axp806_cells[] = { static struct mfd_cell axp809_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp809_pek_resources), .resources = axp809_pek_resources, }, { @@ -873,7 +873,7 @@ static struct mfd_cell axp809_cells[] = { static struct mfd_cell axp813_cells[] = { { - .name = "axp20x-pek", + .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), .resources = axp803_pek_resources, } -- cgit From b0f3ab20e76499db12b0bbadb5737d9870f10418 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 18 Jul 2017 15:22:19 +0200 Subject: mfd: syscon: atmel-smc: Add helper to retrieve register layout For HSMC controller, the register layout depends on the device i.e. the offset of setup, pulse, cycle, mode and timings registers is not the same. An helper is added to provide the correct register layout. Fixes: fe9d7cb22ef3 ("mfd: syscon: atmel-smc: Add new helpers to ease SMC regs manipulation") Suggested-by: Boris Brezillon Signed-off-by: Ludovic Desroches Acked-by: Boris Brezillon Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Signed-off-by: Lee Jones --- drivers/mfd/atmel-smc.c | 67 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 14 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index 20cc0ea470fa..7d77948567d7 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -258,19 +258,21 @@ 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 + * @layout: the layout of registers * @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) +void atmel_hsmc_cs_conf_apply(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *layout, + 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); + regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup); + regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse); + regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle); + regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings); + regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode); } EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply); @@ -297,18 +299,55 @@ 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 + * @layout: the layout of registers * @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) +void atmel_hsmc_cs_conf_get(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *layout, + 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); + regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup); + regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse); + regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle); + regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings); + regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode); } EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get); + +static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = { + .timing_regs_offset = 0x600, +}; + +static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = { + .timing_regs_offset = 0x700, +}; + +static const struct of_device_id atmel_smc_ids[] = { + { .compatible = "atmel,at91sam9260-smc", .data = NULL }, + { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout }, + { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout }, + { /* sentinel */ }, +}; + +/** + * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers + * @np: the HSMC regmap + * + * Retrieve the layout of HSMC registers. + * + * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer + * in HSMC case, otherwise ERR_PTR(-EINVAL). + */ +const struct atmel_hsmc_reg_layout * +atmel_hsmc_get_reg_layout(struct device_node *np) +{ + const struct of_device_id *match; + + match = of_match_node(atmel_smc_ids, np); + + return match ? match->data : ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout); -- cgit From d9018976cdb6eefc62a7ba79a405f6c9661b08a7 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 28 Jul 2017 13:50:42 +0300 Subject: mfd: lpc_ich: Do not touch SPI-NOR write protection bit on Haswell/Broadwell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on Lenovo Thinkpad Yoga, the BIOS seems to monitor the SPI-NOR write protection bit and if it is flipped to read/write it assumes the BIOS configuration was changed on next reboot. It then, for unknown reasons, resets the BIOS settings back to default. We can prevent this by just leaving the write protection bit intact and let the SPI-NOR driver know whether the device is writable or not. In case of this particular Lenovo the SPI-NOR flash will be exposed as read-only. Fixes: ff00d7a32a1b ("mfd: lpc_ich: Add support for SPI serial flash host controller") Link: https://bugzilla.kernel.org/show_bug.cgi?id=195951 Reported-by: Abdó Roig-Marange Signed-off-by: Mika Westerberg Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 773f1554d2f9..450ae36645aa 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -1119,17 +1119,7 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->start = spi_base + SPIBASE_LPT; res->end = res->start + SPIBASE_LPT_SZ - 1; - /* - * Try to make the flash chip writeable now by - * setting BCR_WPD. It it fails we tell the driver - * that it can only read the chip. - */ pci_read_config_dword(dev, BCR, &bcr); - if (!(bcr & BCR_WPD)) { - bcr |= BCR_WPD; - pci_write_config_dword(dev, BCR, bcr); - pci_read_config_dword(dev, BCR, &bcr); - } info->writeable = !!(bcr & BCR_WPD); } break; -- cgit From 9bbf6a15ce19dd947b7fa6ad4095931ab3682da8 Mon Sep 17 00:00:00 2001 From: Rajmohan Mani Date: Fri, 28 Jul 2017 17:30:24 -0700 Subject: mfd: Add support for TPS68470 device The TPS68470 device is an advanced power management unit that powers a Compact Camera Module (CCM), generates clocks for image sensors, drives a dual LED for Flash and incorporates two LED drivers for general purpose indicators. This patch adds support for TPS68470 mfd device. Signed-off-by: Rajmohan Mani Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 18 +++++++++ drivers/mfd/Makefile | 1 + drivers/mfd/tps68470.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 drivers/mfd/tps68470.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 79e4ec6f19a8..4f57725a02ea 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1352,6 +1352,24 @@ config MFD_TPS65217 This driver can also be built as a module. If so, the module will be called tps65217. +config MFD_TPS68470 + bool "TI TPS68470 Power Management / LED chips" + depends on ACPI && I2C=y + select MFD_CORE + select REGMAP_I2C + select I2C_DESIGNWARE_PLATFORM + help + If you say yes here you get support for the TPS68470 series of + Power Management / LED chips. + + These include voltage regulators, LEDs and other features + that are often used in portable devices. + + This option is a bool as it provides an ACPI operation + region, which must be available before any of the devices + using this are probed. This option also configures the + designware-i2c driver to be built-in, for the same reason. + config MFD_TI_LP873X tristate "TI LP873X Power Management IC" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 21e19a5f3f3c..c3d0a1b39bb6 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_MFD_TPS65910) += tps65910.o obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o +obj-$(CONFIG_MFD_TPS68470) += tps68470.o obj-$(CONFIG_MFD_TPS80031) += tps80031.o obj-$(CONFIG_MENELAUS) += menelaus.o diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c new file mode 100644 index 000000000000..189efaea054c --- /dev/null +++ b/drivers/mfd/tps68470.c @@ -0,0 +1,106 @@ +/* + * TPS68470 chip Parent driver + * + * Copyright (C) 2017 Intel Corporation + * + * Authors: + * Rajmohan Mani + * Tianshu Qiu + * Jian Xu Zheng + * Yuning Pu + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell tps68470s[] = { + { .name = "tps68470-gpio" }, + { .name = "tps68470_pmic_opregion" }, +}; + +static const struct regmap_config tps68470_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TPS68470_REG_MAX, +}; + +static int tps68470_chip_init(struct device *dev, struct regmap *regmap) +{ + unsigned int version; + int ret; + + /* Force software reset */ + ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK); + if (ret) + return ret; + + ret = regmap_read(regmap, TPS68470_REG_REVID, &version); + if (ret) { + dev_err(dev, "Failed to read revision register: %d\n", ret); + return ret; + } + + dev_info(dev, "TPS68470 REVID: 0x%x\n", version); + + return 0; +} + +static int tps68470_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "devm_regmap_init_i2c Error %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + i2c_set_clientdata(client, regmap); + + ret = tps68470_chip_init(dev, regmap); + if (ret < 0) { + dev_err(dev, "TPS68470 Init Error %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tps68470s, + ARRAY_SIZE(tps68470s), NULL, 0, NULL); + if (ret < 0) { + dev_err(dev, "devm_mfd_add_devices failed: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct acpi_device_id tps68470_acpi_ids[] = { + {"INT3472"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids); + +static struct i2c_driver tps68470_driver = { + .driver = { + .name = "tps68470", + .acpi_match_table = tps68470_acpi_ids, + }, + .probe_new = tps68470_probe, +}; +builtin_i2c_driver(tps68470_driver); -- cgit From ea3993a9bdb77375a91e88b5e5f853474b095dd5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Jul 2017 18:58:15 +0800 Subject: mfd: lp87565: Convert to use devm_mfd_add_devices() This fixes missing mfd_remove_devices() call when unload the module. Signed-off-by: Axel Lin Reviewed-by: Keerthy Signed-off-by: Lee Jones --- drivers/mfd/lp87565.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c index 340ad0c63744..32d2a07d4354 100644 --- a/drivers/mfd/lp87565.c +++ b/drivers/mfd/lp87565.c @@ -73,10 +73,9 @@ static int lp87565_probe(struct i2c_client *client, i2c_set_clientdata(client, lp87565); - ret = mfd_add_devices(lp87565->dev, PLATFORM_DEVID_AUTO, lp87565_cells, - ARRAY_SIZE(lp87565_cells), NULL, 0, NULL); - - return ret; + return devm_mfd_add_devices(lp87565->dev, PLATFORM_DEVID_AUTO, + lp87565_cells, ARRAY_SIZE(lp87565_cells), + NULL, 0, NULL); } static const struct i2c_device_id lp87565_id_table[] = { -- cgit From 1ae14f8e84727d158cb6d27760e6f17eb9994cff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 14 Aug 2017 22:02:23 +0200 Subject: mfd: intel_soc_pmic_chtwc: Turn Kconfig option into a bool The PMIC provides ACPI OpRegions which must be available for other drivers' PS0 / PS3 methods early-on as such it must be builtin as the Kconfig help text already states. Somehow its Kconfig option ended up being a tristate though, this fixes this. Signed-off-by: Hans de Goede Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 4f57725a02ea..7bc4ee1f9c10 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -495,7 +495,7 @@ config INTEL_SOC_PMIC_BXTWC on these systems. config INTEL_SOC_PMIC_CHTWC - tristate "Support for Intel Cherry Trail Whiskey Cove PMIC" + bool "Support for Intel Cherry Trail Whiskey Cove PMIC" depends on ACPI && HAS_IOMEM && I2C=y && COMMON_CLK depends on X86 || COMPILE_TEST select MFD_CORE -- cgit From b62d8dbe419893b7aee5fac282e1da8c811cfcfb Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 8 Aug 2017 15:24:56 +0530 Subject: mfd: t7l66xb: Handle return value of clk_prepare_enable clk_prepare_enable() can fail here and we must check its return value. we must disable clock, if t7l66xb_probe is not successful. Signed-off-by: Arvind Yadav Signed-off-by: Lee Jones --- drivers/mfd/t7l66xb.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 22c811396edc..43d8683266de 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -86,8 +86,11 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc) struct t7l66xb *t7l66xb = platform_get_drvdata(dev); unsigned long flags; u8 dev_ctl; + int ret; - clk_prepare_enable(t7l66xb->clk32k); + ret = clk_prepare_enable(t7l66xb->clk32k); + if (ret) + return ret; raw_spin_lock_irqsave(&t7l66xb->lock, flags); @@ -286,8 +289,12 @@ static int t7l66xb_resume(struct platform_device *dev) { struct t7l66xb *t7l66xb = platform_get_drvdata(dev); struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); + int ret; + + ret = clk_prepare_enable(t7l66xb->clk48m); + if (ret) + return ret; - clk_prepare_enable(t7l66xb->clk48m); if (pdata && pdata->resume) pdata->resume(dev); @@ -361,7 +368,9 @@ static int t7l66xb_probe(struct platform_device *dev) goto err_ioremap; } - clk_prepare_enable(t7l66xb->clk48m); + ret = clk_prepare_enable(t7l66xb->clk48m); + if (ret) + goto err_clk_enable; if (pdata->enable) pdata->enable(dev); @@ -386,6 +395,8 @@ static int t7l66xb_probe(struct platform_device *dev) return 0; t7l66xb_detach_irq(dev); + clk_disable_unprepare(t7l66xb->clk48m); +err_clk_enable: iounmap(t7l66xb->scr); err_ioremap: release_resource(&t7l66xb->rscr); -- cgit From e4b91470bd79b988253ec00590e5b554042af4a7 Mon Sep 17 00:00:00 2001 From: "Florian R. Hölzlwimmer" Date: Sat, 19 Aug 2017 15:26:49 +0200 Subject: mfd: intel-lpss: Add missing PCI ID for Intel Sunrise Point LPSS devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a missing PCI ID of the Intel Sunrise Point chipset to the Intel LPSS driver. It fixes a bug causing the touchpad of the Lenovo Yoga 720-15 not to be recognized. See also bug 1700657 on bugs.launchpad.net. Many thanks to CoolStar, who found this solution! Reported-by: CoolStar Tested-by: Mike Schwartz Tested-by: Björn Dahlgren Signed-off-by: Florian R. Hölzlwimmer Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss-pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index ad388bb056cd..d1c46de89eb4 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -221,6 +221,7 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa162), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, /* KBL-H */ { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&spt_uart_info }, -- cgit From 6af42e5dd008535b9c1a7d2538ab19617538c3eb Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 20 Aug 2017 00:59:37 +0530 Subject: mfd: da9055: Constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Lee Jones --- drivers/mfd/da9055-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index b53e100f577c..8169a5c2fa20 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -62,7 +62,7 @@ static int da9055_i2c_remove(struct i2c_client *i2c) * purposes separate). As a result there are specific DA9055 ids for PMIC * and CODEC, which must be different to operate together. */ -static struct i2c_device_id da9055_i2c_id[] = { +static const struct i2c_device_id da9055_i2c_id[] = { {"da9055-pmic", 0}, { } }; -- cgit From 0b471aaa0e1a8f3d06c76b52c3a903f817d7052e Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Sun, 23 Jul 2017 23:02:19 -0700 Subject: mfd: intel-lpss: Put I2C and SPI controllers into reset state on suspend Commit 274e43edcda6f ("mfd: intel-lpss: Do not put device in reset state on suspend") changed the behavior on suspend by not putting LPSS controllers into reset. This was done because S3/S0ix fail if UART device is put into reset and no_console_suspend flag is enabled. Because of the above change, I2C controller gets into a bad state if it observes that the I2C lines are pulled low when power to I2C device is cut off during suspend (generally, I2C lines are pulled to power rail of the I2C device in order to ensure that there is no leakage because of the pulls when device is turned off). This results in the controller timing out for all future I2C operations after resume. It is primarily because of the following sequence of operations: During suspend: 1. I2C controller is disabled, but it is not put into reset. 2. Power to I2C device is cut off. 3. #2 results in the I2C lines being pulled low. ==> At this point the I2C controller gets into a bad state On resume: 1. Power to I2C device is enabled. 2. #2 results in the I2C lines being pulled high. 3. I2C controller is enabled. However, even after enabling the I2C controller, all future I2C xfers fail since the controller is in a bad state and does not attempt to make any transactions and hence times out. In order to ensure that the controller does not get into a bad state, this change puts it into reset if the controller type is not UART. With this change, the order of operations is: During suspend: 1. I2C controller is disabled and put into reset. 2. Power to I2C device is cut off. 3. #2 results in the I2C lines being pulled low. On resume: 1. Power to I2C device is enabled. 2. #2 results in the I2C lines being pulled high. 3. I2C controller is enabled and taken out of reset. Signed-off-by: Furquan Shaikh Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 70c646b0097d..0e0ab9bb1530 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -502,6 +502,14 @@ int intel_lpss_suspend(struct device *dev) for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) lpss->priv_ctx[i] = readl(lpss->priv + i * 4); + /* + * If the device type is not UART, then put the controller into + * reset. UART cannot be put into reset since S3/S0ix fail when + * no_console_suspend flag is enabled. + */ + if (lpss->type != LPSS_DEV_UART) + writel(0, lpss->priv + LPSS_PRIV_RESETS); + return 0; } EXPORT_SYMBOL_GPL(intel_lpss_suspend); -- cgit From 7e1372a4ceb80dafef5ff661a66d7b3a1a8c0a75 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 23:25:27 +0530 Subject: mfd: da9052: Constify spi_device_id spi_device_id are not supposed to change at runtime. All functions working with spi_device_id provided by work with const spi_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Lee Jones --- drivers/mfd/da9052-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index b9ea1b27db64..abfb11818fdc 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -67,7 +67,7 @@ static int da9052_spi_remove(struct spi_device *spi) return 0; } -static struct spi_device_id da9052_spi_id[] = { +static const struct spi_device_id da9052_spi_id[] = { {"da9052", DA9052}, {"da9053-aa", DA9053_AA}, {"da9053-ba", DA9053_BA}, -- cgit From 993dc737c0996c163325961fb62a0ed9fd0308b4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Aug 2017 16:44:51 +0200 Subject: mfd: omap-usb-tll: Fix register offsets gcc-8 notices that the register number calculation is wrong when the offset is an 'u8' but the number is larger than 256: drivers/mfd/omap-usb-tll.c: In function 'omap_tll_init': drivers/mfd/omap-usb-tll.c:90:46: error: overflow in conversion from 'int' to 'u8 {aka unsigned char}' chages value from 'i * 256 + 2070' to '22' [-Werror=overflow] This addresses it by always using a 32-bit offset number for the register. This is apparently an old problem that previous compilers did not find. Fixes: 16fa3dc75c22 ("mfd: omap-usb-tll: HOST TLL platform driver") Signed-off-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-tll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 6f5300b0eb31..44a5d66314c6 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -131,12 +131,12 @@ static inline u32 usbtll_read(void __iomem *base, u32 reg) return readl_relaxed(base + reg); } -static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) +static inline void usbtll_writeb(void __iomem *base, u32 reg, u8 val) { writeb_relaxed(val, base + reg); } -static inline u8 usbtll_readb(void __iomem *base, u8 reg) +static inline u8 usbtll_readb(void __iomem *base, u32 reg) { return readb_relaxed(base + reg); } -- cgit From 4d9ed62ab1425d85b25d04096cb4e74117e6dc24 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 4 Sep 2017 15:22:41 +0200 Subject: mfd: intel_soc_pmic: Export separate mfd-cell configs for BYT and CHT Both Bay and Cherry Trail devices may be used together with a Crystal Cove PMIC. Each platform has its own variant of the PMIC, which both use the same ACPI HID, but they are not 100% compatible. Looking at the android x86 kernel sources where most of the Crystal Cove code comes from, it talks about "Valley View", "Bay Trail" and / or BYT without ever mentioning Cherry Trail, with the exception of the regulator driver. The Asus Zenfone-2 kernel code has 2 regulator drivers, one for Crystal Cove and one for what it calls Crystal Cove Plus. The Crystal Cove Plus regulator driver is the only one to mention Cherry Trail and that driver uses different register addresses then the normal (Bay Trail) Crystal Cove regulator driver, showing that at least the regulator register addresses are different. The GPIO code should work on both, and the PWM code is known to work on both and is necessary for backlight control on some Cherry Trail devices. Testing has shown that the ACPI OpRegion code otoh is causing problems on Cherry Trail devices, which is not surprising as it deals with the regulators and those have different register addresses on CHT. Specifically the ACPI OpRegion code causes the external microsd slot on a Dell Venue 8 5855 (Cherry Trail version) to not work and the eMMC to become unreliable and throw lots of errors. This commit replaces the single mfd_cell array currently used for Crystal Cove with 2 separate arrays, one for the Bay Trail variant and one for the Cherry Trail variant, note that the Cherry Trail version of the array only contains gpio and pwm cells. The PMIC OpRegion cell is deliberately not included and drivers for the other cells in the Bay Trail cell array were never upstreamed. Fixes: 7cf0a66f32 ("mfd: intel_soc_pmic: Crystal Cove support") Reported-and-tested-by: russianneuromancer Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_core.c | 2 +- drivers/mfd/intel_soc_pmic_core.h | 3 ++- drivers/mfd/intel_soc_pmic_crc.c | 27 +++++++++++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 13737be6df35..2234a847370a 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -157,7 +157,7 @@ MODULE_DEVICE_TABLE(i2c, intel_soc_pmic_i2c_id); #if defined(CONFIG_ACPI) static const struct acpi_device_id intel_soc_pmic_acpi_match[] = { - {"INT33FD", (kernel_ulong_t)&intel_soc_pmic_config_crc}, + {"INT33FD", (kernel_ulong_t)&intel_soc_pmic_config_byt_crc}, { }, }; MODULE_DEVICE_TABLE(acpi, intel_soc_pmic_acpi_match); diff --git a/drivers/mfd/intel_soc_pmic_core.h b/drivers/mfd/intel_soc_pmic_core.h index ff2464bc172f..90a1416d4dac 100644 --- a/drivers/mfd/intel_soc_pmic_core.h +++ b/drivers/mfd/intel_soc_pmic_core.h @@ -27,6 +27,7 @@ struct intel_soc_pmic_config { const struct regmap_irq_chip *irq_chip; }; -extern struct intel_soc_pmic_config intel_soc_pmic_config_crc; +extern struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc; +extern struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc; #endif /* __INTEL_SOC_PMIC_CORE_H__ */ diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 4a7494872da2..6d19a6d0fb97 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -80,7 +80,7 @@ static struct resource bcu_resources[] = { }, }; -static struct mfd_cell crystal_cove_dev[] = { +static struct mfd_cell crystal_cove_byt_dev[] = { { .name = "crystal_cove_pwrsrc", .num_resources = ARRAY_SIZE(pwrsrc_resources), @@ -114,6 +114,17 @@ static struct mfd_cell crystal_cove_dev[] = { }, }; +static struct mfd_cell crystal_cove_cht_dev[] = { + { + .name = "crystal_cove_gpio", + .num_resources = ARRAY_SIZE(gpio_resources), + .resources = gpio_resources, + }, + { + .name = "crystal_cove_pwm", + }, +}; + static const struct regmap_config crystal_cove_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -155,10 +166,18 @@ static const struct regmap_irq_chip crystal_cove_irq_chip = { .mask_base = CRYSTAL_COVE_REG_MIRQLVL1, }; -struct intel_soc_pmic_config intel_soc_pmic_config_crc = { +struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc = { + .irq_flags = IRQF_TRIGGER_RISING, + .cell_dev = crystal_cove_byt_dev, + .n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev), + .regmap_config = &crystal_cove_regmap_config, + .irq_chip = &crystal_cove_irq_chip, +}; + +struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc = { .irq_flags = IRQF_TRIGGER_RISING, - .cell_dev = crystal_cove_dev, - .n_cell_devs = ARRAY_SIZE(crystal_cove_dev), + .cell_dev = crystal_cove_cht_dev, + .n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev), .regmap_config = &crystal_cove_regmap_config, .irq_chip = &crystal_cove_irq_chip, }; -- cgit From b01e9348e106544e50691252bf58cde239681f19 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 4 Sep 2017 15:22:42 +0200 Subject: mfd: intel_soc_pmic: Differentiate between Bay and Cherry Trail CRC variants Both Bay and Cherry Trail devices may be used together with a Crystal Cove PMIC. Each platform has its own variant of the PMIC, which both use the same ACPI HID, but they are not 100% compatible. This commits makes the intel_soc_pmic_core code check the _HRV of the ACPI-firmware-node and selects intel_soc_pmic_config_byt_crc resp. intel_soc_pmic_config_cht_crc based on this. This fixes the Bay Trail specific ACPI OpRegion code causing problems on Cherry Trail devices. Specifically this was causing the external microsd slot on a Dell Venue 8 5855 (Cherry Trail version) to not work and the eMMC to become unreliable and throw lots of errors. Fixes: 5165238460 ("mfd: intel_soc_pmic: Core driver") Reported-and-tested-by: russianneuromancer Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 4 ++-- drivers/mfd/intel_soc_pmic_core.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 7bc4ee1f9c10..fc5e4fef89d2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -467,12 +467,12 @@ config LPC_SCH config INTEL_SOC_PMIC bool "Support for Crystal Cove PMIC" - depends on HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK + depends on ACPI && HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK depends on X86 || COMPILE_TEST select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - select I2C_DESIGNWARE_PLATFORM if ACPI + select I2C_DESIGNWARE_PLATFORM help Select this option to enable support for Crystal Cove PMIC on some Intel SoC systems. The PMIC provides ADC, GPIO, diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 2234a847370a..36adf9e8153e 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -16,6 +16,7 @@ * Author: Zhu, Lejun */ +#include #include #include #include @@ -28,6 +29,10 @@ #include #include "intel_soc_pmic_core.h" +/* Crystal Cove PMIC shares same ACPI ID between different platforms */ +#define BYT_CRC_HRV 2 +#define CHT_CRC_HRV 3 + /* Lookup table for the Panel Enable/Disable line as GPIO signals */ static struct gpiod_lookup_table panel_gpio_table = { /* Intel GFX is consumer */ @@ -48,16 +53,33 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) { struct device *dev = &i2c->dev; - const struct acpi_device_id *id; struct intel_soc_pmic_config *config; struct intel_soc_pmic *pmic; + unsigned long long hrv; + acpi_status status; int ret; - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id || !id->driver_data) + /* + * There are 2 different Crystal Cove PMICs a Bay Trail and Cherry + * Trail version, use _HRV to differentiate between the 2. + */ + status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to get PMIC hardware revision\n"); return -ENODEV; - - config = (struct intel_soc_pmic_config *)id->driver_data; + } + + switch (hrv) { + case BYT_CRC_HRV: + config = &intel_soc_pmic_config_byt_crc; + break; + case CHT_CRC_HRV: + config = &intel_soc_pmic_config_cht_crc; + break; + default: + dev_warn(dev, "Unknown hardware rev %llu, assuming BYT\n", hrv); + config = &intel_soc_pmic_config_byt_crc; + } pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) @@ -157,7 +179,7 @@ MODULE_DEVICE_TABLE(i2c, intel_soc_pmic_i2c_id); #if defined(CONFIG_ACPI) static const struct acpi_device_id intel_soc_pmic_acpi_match[] = { - {"INT33FD", (kernel_ulong_t)&intel_soc_pmic_config_byt_crc}, + { "INT33FD" }, { }, }; MODULE_DEVICE_TABLE(acpi, intel_soc_pmic_acpi_match); -- cgit