From 3fb3b3c4b68e33bb4acf42361b6a0db96115de35 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Tue, 25 Jul 2017 14:00:24 +0200 Subject: memory: atmel-ebi: Fix smc cycle xlate converter The converter function for translating ns timings in register values was initialized with a wrong function pointer. This resulted in wrong register values also for the setup and pulse registers when configuring the EBI interface trough dts. Includes a small fix in a comment of the smc driver, which was probably just a copy'n'paste mistake. Signed-off-by: Alexander Dahl Acked-by: Boris Brezillon Acked-by: Lee Jones Signed-off-by: Alexandre Belloni --- drivers/mfd/atmel-smc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index 954cf0f66a31..20cc0ea470fa 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -206,7 +206,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse); * parameter * * This function encodes the @ncycles value as described in the datasheet - * (section "SMC Pulse Register"), and then stores the result in the + * (section "SMC Cycle 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 -- cgit v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 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 v1.2.3 From ebf555111bc11a5da9144e4af524260731a8b968 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 21 Aug 2017 16:54:02 +0200 Subject: mfd: da9052: Make touchscreen registration optional If the touchscreen pins are used as general purpose analogue input, the touchscreen driver should not be used. The pins will be handled by the existing hwmon driver instead. Signed-off-by: Sebastian Reichel Signed-off-by: Lee Jones --- drivers/mfd/da9052-core.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index a88c2065d8ab..a23a3a1c7061 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -518,9 +519,6 @@ static const struct mfd_cell da9052_subdev_info[] = { { .name = "da9052-wled3", }, - { - .name = "da9052-tsi", - }, { .name = "da9052-bat", }, @@ -529,6 +527,10 @@ static const struct mfd_cell da9052_subdev_info[] = { }, }; +static const struct mfd_cell da9052_tsi_subdev_info[] = { + { .name = "da9052-tsi" }, +}; + const struct regmap_config da9052_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -619,9 +621,27 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id) goto err; } + /* + * Check if touchscreen pins are used are analogue input instead + * of having a touchscreen connected to them. The analogue input + * functionality will be provided by hwmon driver (if enabled). + */ + if (!device_property_read_bool(da9052->dev, "dlg,tsi-as-adc")) { + ret = mfd_add_devices(da9052->dev, PLATFORM_DEVID_AUTO, + da9052_tsi_subdev_info, + ARRAY_SIZE(da9052_tsi_subdev_info), + NULL, 0, NULL); + if (ret) { + dev_err(da9052->dev, "failed to add TSI subdev: %d\n", + ret); + goto err; + } + } + return 0; err: + mfd_remove_devices(da9052->dev); da9052_irq_exit(da9052); return ret; -- cgit v1.2.3 From 0f0fc5c090055983163ed8e7b3a73980e128048c Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 15 Aug 2017 09:30:05 +0100 Subject: Revert "mfd: da9061: Fix to remove BBAT_CONT register from chip model" This patch was applied to the MFD twice, causing unwanted behavour. This reverts commit b77eb79acca3203883e8d8dbc7f2b842def1bff8. Fixes: b77eb79acca3 ("mfd: da9061: Fix to remove BBAT_CONT register from chip model") Reported-by: Steve Twiss Reviewed-by: Steve Twiss Signed-off-by: Lee Jones --- drivers/mfd/da9062-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index fbe0f245ce8e..fe1811523e4a 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -644,6 +644,9 @@ static const struct regmap_range da9062_aa_readable_ranges[] = { }, { .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, @@ -720,6 +723,9 @@ static const struct regmap_range da9062_aa_writeable_ranges[] = { }, { .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, -- cgit v1.2.3 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 v1.2.3 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 v1.2.3