From 65433fd561f089f232758efc2c6566b6b6febb47 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 20 Mar 2016 18:53:57 +0000 Subject: [PATCH 01/73] mfd: da9063: Remove unused array mask_events_buf mask_events_buf is not used, so remove this redundant array. Signed-off-by: Colin Ian King Signed-off-by: Lee Jones --- drivers/mfd/da9063-irq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c index 26302634633c..0aa760e155ec 100644 --- a/drivers/mfd/da9063-irq.c +++ b/drivers/mfd/da9063-irq.c @@ -27,8 +27,6 @@ #define DA9063_REG_EVENT_D_OFFSET 3 #define EVENTS_BUF_LEN 4 -static const u8 mask_events_buf[] = { [0 ... (EVENTS_BUF_LEN - 1)] = ~0 }; - struct da9063_irq_data { u16 reg; u8 mask; From 7f0c5ae18d649ed2f4978cbf07c02a0ff732f23e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 19 Feb 2016 10:42:10 +0200 Subject: [PATCH 02/73] mfd: intel_quark_i2c_gpio: Remove clock tree on error path There is a potential resource leak in case when ->probe() fails. We have to unregister and remove clock tree which is done here. This is a follow up to previously pushed commit c4726abce63b ("mfd: intel_quark_i2c_gpio: Use clkdev_create()") that prevents double free() when clkdev_drop() followed by kfree() in devm_kcalloc() release stage. I leave Fixes tag here, but the backporting will require to backport the commit c4726abce63b ("mfd: intel_quark_i2c_gpio: Use clkdev_create()") first. Cc: stable@vger.kernel.org Fixes: 60ae5b9f5cdd (mfd: intel_quark_i2c_gpio: Add Intel Quark X1000 I2C-GPIO MFD Driver) Signed-off-by: Andy Shevchenko Acked-by: Stephen Boyd Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index bdc5e27222c0..7450f5d8770c 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -139,6 +139,7 @@ static int intel_quark_register_i2c_clk(struct intel_quark_mfd *quark_mfd) INTEL_QUARK_I2C_CONTROLLER_CLK); if (!quark_mfd->i2c_clk_lookup) { + clk_unregister(quark_mfd->i2c_clk); dev_err(&pdev->dev, "Fixed clk register failed\n"); return -ENOMEM; } @@ -150,7 +151,7 @@ static void intel_quark_unregister_i2c_clk(struct pci_dev *pdev) { struct intel_quark_mfd *quark_mfd = dev_get_drvdata(&pdev->dev); - if (!quark_mfd->i2c_clk || !quark_mfd->i2c_clk_lookup) + if (!quark_mfd->i2c_clk_lookup) return; clkdev_drop(quark_mfd->i2c_clk_lookup); @@ -246,25 +247,33 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL); if (!quark_mfd) return -ENOMEM; + quark_mfd->pdev = pdev; + dev_set_drvdata(&pdev->dev, quark_mfd); ret = intel_quark_register_i2c_clk(quark_mfd); if (ret) return ret; - dev_set_drvdata(&pdev->dev, quark_mfd); - ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]); if (ret) - return ret; + goto err_unregister_i2c_clk; ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]); if (ret) - return ret; + goto err_unregister_i2c_clk; - return mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, - ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, - NULL); + ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, + ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, + NULL); + if (ret) + goto err_unregister_i2c_clk; + + return 0; + +err_unregister_i2c_clk: + intel_quark_unregister_i2c_clk(pdev); + return ret; } static void intel_quark_mfd_remove(struct pci_dev *pdev) From 9caac886397bdfd6c1a6b48493db6cd95bce313c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 19 Feb 2016 10:42:11 +0200 Subject: [PATCH 03/73] mfd: intel_quark_i2c_gpio: Switch to use struct device * There is no need to pass struct pci_dev * to intel_quark_register_i2c_clk() and intel_quark_unregister_i2c_clk(). Change the parameter to struct device *. As a result store it in the private struct instead of struct pci_dev *. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 7450f5d8770c..24c2d291b1dc 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -53,7 +53,7 @@ #define INTEL_QUARK_I2C_CLK_HZ 33000000 struct intel_quark_mfd { - struct pci_dev *pdev; + struct device *dev; struct clk *i2c_clk; struct clk_lookup *i2c_clk_lookup; }; @@ -123,12 +123,12 @@ static const struct pci_device_id intel_quark_mfd_ids[] = { }; MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids); -static int intel_quark_register_i2c_clk(struct intel_quark_mfd *quark_mfd) +static int intel_quark_register_i2c_clk(struct device *dev) { - struct pci_dev *pdev = quark_mfd->pdev; + struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev); struct clk *i2c_clk; - i2c_clk = clk_register_fixed_rate(&pdev->dev, + i2c_clk = clk_register_fixed_rate(dev, INTEL_QUARK_I2C_CONTROLLER_CLK, NULL, CLK_IS_ROOT, INTEL_QUARK_I2C_CLK_HZ); if (IS_ERR(i2c_clk)) @@ -140,16 +140,16 @@ static int intel_quark_register_i2c_clk(struct intel_quark_mfd *quark_mfd) if (!quark_mfd->i2c_clk_lookup) { clk_unregister(quark_mfd->i2c_clk); - dev_err(&pdev->dev, "Fixed clk register failed\n"); + dev_err(dev, "Fixed clk register failed\n"); return -ENOMEM; } return 0; } -static void intel_quark_unregister_i2c_clk(struct pci_dev *pdev) +static void intel_quark_unregister_i2c_clk(struct device *dev) { - struct intel_quark_mfd *quark_mfd = dev_get_drvdata(&pdev->dev); + struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev); if (!quark_mfd->i2c_clk_lookup) return; @@ -248,10 +248,10 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, if (!quark_mfd) return -ENOMEM; - quark_mfd->pdev = pdev; + quark_mfd->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, quark_mfd); - ret = intel_quark_register_i2c_clk(quark_mfd); + ret = intel_quark_register_i2c_clk(&pdev->dev); if (ret) return ret; @@ -272,13 +272,13 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, return 0; err_unregister_i2c_clk: - intel_quark_unregister_i2c_clk(pdev); + intel_quark_unregister_i2c_clk(&pdev->dev); return ret; } static void intel_quark_mfd_remove(struct pci_dev *pdev) { - intel_quark_unregister_i2c_clk(pdev); + intel_quark_unregister_i2c_clk(&pdev->dev); mfd_remove_devices(&pdev->dev); } From ee414de525a9abf29e8a1b0c1b6f79f9e875213a Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Sun, 13 Mar 2016 03:02:58 +0200 Subject: [PATCH 04/73] mfd: core: Fix ACPI child matching by _HID/_CID If MDF child devices have separate ACPI nodes identified by _HID/_CID, they will not be assigned the intended ACPI companion. acpi_match_device_ids will return 0 if a the child device matches the _HID/_CID, so this patch changes the matching condition to check for 0 on success. Signed-off-by: Irina Tirdea Acked-by: Mika Westerberg Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 88bd1b1e47be..409da01effcd 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -107,7 +107,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id)); list_for_each_entry(child, &parent->children, node) { - if (acpi_match_device_ids(child, ids)) { + if (!acpi_match_device_ids(child, ids)) { adev = child; break; } From adae28c59a6a71a971ffed713550911546df0e20 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Mar 2016 11:36:53 +0100 Subject: [PATCH 05/73] mfd: syscon: Include errno.h from header The syscon header uses the ENOTSUPP error constant, but doesn't include the header that defines it. This causes a build error after the imx pinctrl driver started using syscon: include/linux/mfd/syscon.h: In function 'syscon_node_to_regmap': include/linux/mfd/syscon.h:32:18: error: 'ENOTSUPP' undeclared (first use in this function) return ERR_PTR(-ENOTSUPP); ^~~~~~~~ This adds the missing #include. Signed-off-by: Arnd Bergmann Fixes: 8626ada871f1 ("pinctrl: imx: attach iomuxc device to gpr syscon") Signed-off-by: Lee Jones --- include/linux/mfd/syscon.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index 1088149be0c9..40a76b97b7ab 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -16,6 +16,7 @@ #define __LINUX_MFD_SYSCON_H__ #include +#include struct device_node; From 22aab38e7b59fd79ce1045006be69a9abab58e5a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 11 Mar 2016 11:11:39 +0300 Subject: [PATCH 06/73] mfd: lp8788-irq: Uninitialized variable in irq handler Instead to being true/false, the "handled" is true/uninitialized. Presumably this doesn't cause that many problems in real life because normally we handle the IRQ. Fixes: eea6b7cc53aa ('mfd: Add lp8788 mfd driver') Signed-off-by: Dan Carpenter Acked-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/lp8788-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c index c7a9825aa4ce..792d51bae20f 100644 --- a/drivers/mfd/lp8788-irq.c +++ b/drivers/mfd/lp8788-irq.c @@ -112,7 +112,7 @@ static irqreturn_t lp8788_irq_handler(int irq, void *ptr) struct lp8788_irq_data *irqd = ptr; struct lp8788 *lp = irqd->lp; u8 status[NUM_REGS], addr, mask; - bool handled; + bool handled = false; int i; if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS)) From c796c50b9c20b586cd8c3e3a57cea4f0762a60fc Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Tue, 5 Apr 2016 09:41:47 +0100 Subject: [PATCH 07/73] mfd: da9063: Remove unused struct da9063_irq_data and define EVENTS_BUF_LEN The structure da9063_irq_data and define EVENTS_BUF_LEN are not used, so remove the redundant entries. Signed-off-by: Steve Twiss Signed-off-by: Lee Jones --- drivers/mfd/da9063-irq.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c index 0aa760e155ec..7e903fcb8813 100644 --- a/drivers/mfd/da9063-irq.c +++ b/drivers/mfd/da9063-irq.c @@ -25,12 +25,6 @@ #define DA9063_REG_EVENT_B_OFFSET 1 #define DA9063_REG_EVENT_C_OFFSET 2 #define DA9063_REG_EVENT_D_OFFSET 3 -#define EVENTS_BUF_LEN 4 - -struct da9063_irq_data { - u16 reg; - u8 mask; -}; static const struct regmap_irq da9063_irqs[] = { /* DA9063 event A register */ From 073d4aca342029fc62fefa500bb11a556c5f7223 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 4 Apr 2016 16:54:18 +0900 Subject: [PATCH 08/73] mfd: max77693: Allow building as a module The consumer of max77693 regulators on Trats2 board (samsung-usb2-phy driver) supports deferred probing so the max77693 main MFD driver can be built now as a module. This gives more flexibility and removes manual ordering of init calls. Suggested-by: Paul Gortmaker Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 4 ++-- drivers/mfd/max77693.c | 14 ++------------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index eea61e349e26..aa1e7c3f82ee 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -543,8 +543,8 @@ config MFD_MAX77686 of the device. config MFD_MAX77693 - bool "Maxim Semiconductor MAX77693 PMIC Support" - depends on I2C=y + tristate "Maxim Semiconductor MAX77693 PMIC Support" + depends on I2C select MFD_CORE select REGMAP_I2C select REGMAP_IRQ diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index b83b7a7da1ae..78e501feb96c 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -368,6 +368,7 @@ static const struct of_device_id max77693_dt_match[] = { { .compatible = "maxim,max77693" }, {}, }; +MODULE_DEVICE_TABLE(of, max77693_dt_match); #endif static struct i2c_driver max77693_i2c_driver = { @@ -381,18 +382,7 @@ static struct i2c_driver max77693_i2c_driver = { .id_table = max77693_i2c_id, }; -static int __init max77693_i2c_init(void) -{ - return i2c_add_driver(&max77693_i2c_driver); -} -/* init early so consumer devices can complete system boot */ -subsys_initcall(max77693_i2c_init); - -static void __exit max77693_i2c_exit(void) -{ - i2c_del_driver(&max77693_i2c_driver); -} -module_exit(max77693_i2c_exit); +module_i2c_driver(max77693_i2c_driver); MODULE_DESCRIPTION("MAXIM 77693 multi-function core driver"); MODULE_AUTHOR("SangYoung, Son "); From dedf24a28da67f6bf814cb5d05a5d12bb39093dc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 25 Mar 2016 14:27:09 +0000 Subject: [PATCH 09/73] mfd: arizona: Fix lockdep recursion warning on set_irq_wake Avoid a false recursive locking warning from lockdep by adding a lock class for the arizona IRQ chip. Signed-off-by: Charles Keepax Acked-by: Thomas Gleixner Signed-off-by: Lee Jones --- drivers/mfd/arizona-irq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 5fef014920a3..edeb4951366a 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -168,12 +168,15 @@ static struct irq_chip arizona_irq_chip = { .irq_set_wake = arizona_irq_set_wake, }; +static struct lock_class_key arizona_irq_lock_class; + static int arizona_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct arizona *data = h->host_data; irq_set_chip_data(virq, data); + irq_set_lockdep_class(virq, &arizona_irq_lock_class); irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq); irq_set_nested_thread(virq, 1); irq_set_noprobe(virq); From 20147f0d4f50f6f0d1fbe1815fe3d4d0a6444a70 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 29 Mar 2016 17:22:26 +0800 Subject: [PATCH 10/73] mfd: axp20x: Add support for AXP809 PMIC The X-Powers AXP809 is a new PMIC that is paired with Allwinner's A80 SoC, along with a slave AXP806 PMIC. This PMIC is quite similar to the earlier AXP223, though the interrupts and regulator have changed a bit. This patch adds support for the interrupts and power button of the PMIC. Signed-off-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- drivers/mfd/axp20x-rsb.c | 1 + drivers/mfd/axp20x.c | 79 ++++++++++++++++++++++++++++++++++++++ include/linux/mfd/axp20x.h | 59 ++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c index 28c20247c112..a407527bcd09 100644 --- a/drivers/mfd/axp20x-rsb.c +++ b/drivers/mfd/axp20x-rsb.c @@ -61,6 +61,7 @@ static int axp20x_rsb_remove(struct sunxi_rsb_device *rdev) static const struct of_device_id axp20x_rsb_of_match[] = { { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, + { .compatible = "x-powers,axp809", .data = (void *)AXP809_ID }, { }, }; MODULE_DEVICE_TABLE(of, axp20x_rsb_of_match); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index a57d6e940610..1ce923277cc8 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -37,6 +37,7 @@ static const char * const axp20x_model_names[] = { "AXP221", "AXP223", "AXP288", + "AXP809", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -85,6 +86,7 @@ static const struct regmap_access_table axp20x_volatile_table = { .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), }; +/* AXP22x ranges are shared with the AXP809, as they cover the same range */ static const struct regmap_range axp22x_writeable_ranges[] = { regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1), @@ -211,6 +213,20 @@ static struct resource axp288_fuel_gauge_resources[] = { }, }; +static struct resource axp809_pek_resources[] = { + { + .name = "PEK_DBR", + .start = AXP809_IRQ_PEK_RIS_EDGE, + .end = AXP809_IRQ_PEK_RIS_EDGE, + .flags = IORESOURCE_IRQ, + }, { + .name = "PEK_DBF", + .start = AXP809_IRQ_PEK_FAL_EDGE, + .end = AXP809_IRQ_PEK_FAL_EDGE, + .flags = IORESOURCE_IRQ, + }, +}; + static const struct regmap_config axp152_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -378,6 +394,41 @@ static const struct regmap_irq axp288_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1), }; +static const struct regmap_irq axp809_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP809, ACIN_OVER_V, 0, 7), + INIT_REGMAP_IRQ(AXP809, ACIN_PLUGIN, 0, 6), + INIT_REGMAP_IRQ(AXP809, ACIN_REMOVAL, 0, 5), + INIT_REGMAP_IRQ(AXP809, VBUS_OVER_V, 0, 4), + INIT_REGMAP_IRQ(AXP809, VBUS_PLUGIN, 0, 3), + INIT_REGMAP_IRQ(AXP809, VBUS_REMOVAL, 0, 2), + INIT_REGMAP_IRQ(AXP809, VBUS_V_LOW, 0, 1), + INIT_REGMAP_IRQ(AXP809, BATT_PLUGIN, 1, 7), + INIT_REGMAP_IRQ(AXP809, BATT_REMOVAL, 1, 6), + INIT_REGMAP_IRQ(AXP809, BATT_ENT_ACT_MODE, 1, 5), + INIT_REGMAP_IRQ(AXP809, BATT_EXIT_ACT_MODE, 1, 4), + INIT_REGMAP_IRQ(AXP809, CHARG, 1, 3), + INIT_REGMAP_IRQ(AXP809, CHARG_DONE, 1, 2), + INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_HIGH, 2, 7), + INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_HIGH_END, 2, 6), + INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_LOW, 2, 5), + INIT_REGMAP_IRQ(AXP809, BATT_CHG_TEMP_LOW_END, 2, 4), + INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_HIGH, 2, 3), + INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_HIGH_END, 2, 2), + INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_LOW, 2, 1), + INIT_REGMAP_IRQ(AXP809, BATT_ACT_TEMP_LOW_END, 2, 0), + INIT_REGMAP_IRQ(AXP809, DIE_TEMP_HIGH, 3, 7), + INIT_REGMAP_IRQ(AXP809, LOW_PWR_LVL1, 3, 1), + INIT_REGMAP_IRQ(AXP809, LOW_PWR_LVL2, 3, 0), + INIT_REGMAP_IRQ(AXP809, TIMER, 4, 7), + INIT_REGMAP_IRQ(AXP809, PEK_RIS_EDGE, 4, 6), + INIT_REGMAP_IRQ(AXP809, PEK_FAL_EDGE, 4, 5), + INIT_REGMAP_IRQ(AXP809, PEK_SHORT, 4, 4), + INIT_REGMAP_IRQ(AXP809, PEK_LONG, 4, 3), + INIT_REGMAP_IRQ(AXP809, PEK_OVER_OFF, 4, 2), + INIT_REGMAP_IRQ(AXP809, GPIO1_INPUT, 4, 1), + INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0), +}; + static const struct regmap_irq_chip axp152_regmap_irq_chip = { .name = "axp152_irq_chip", .status_base = AXP152_IRQ1_STATE, @@ -428,6 +479,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = { }; +static const struct regmap_irq_chip axp809_regmap_irq_chip = { + .name = "axp809", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, + .mask_base = AXP20X_IRQ1_EN, + .mask_invert = true, + .init_ack_masked = true, + .irqs = axp809_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp809_regmap_irqs), + .num_regs = 5, +}; + static struct mfd_cell axp20x_cells[] = { { .name = "axp20x-pek", @@ -572,6 +635,16 @@ static struct mfd_cell axp288_cells[] = { }, }; +static struct mfd_cell axp809_cells[] = { + { + .name = "axp20x-pek", + .num_resources = ARRAY_SIZE(axp809_pek_resources), + .resources = axp809_pek_resources, + }, { + .name = "axp20x-regulator", + }, +}; + static struct axp20x_dev *axp20x_pm_power_off; static void axp20x_power_off(void) { @@ -631,6 +704,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_cfg = &axp288_regmap_config; axp20x->regmap_irq_chip = &axp288_regmap_irq_chip; break; + case AXP809_ID: + axp20x->nr_cells = ARRAY_SIZE(axp809_cells); + axp20x->cells = axp809_cells; + axp20x->regmap_cfg = &axp22x_regmap_config; + axp20x->regmap_irq_chip = &axp809_regmap_irq_chip; + break; default: dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); return -EINVAL; diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index d82e7d51372b..0be4982f08fe 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -20,6 +20,7 @@ enum { AXP221_ID, AXP223_ID, AXP288_ID, + AXP809_ID, NR_AXP20X_VARIANTS, }; @@ -264,6 +265,29 @@ enum { AXP22X_REG_ID_MAX, }; +enum { + AXP809_DCDC1 = 0, + AXP809_DCDC2, + AXP809_DCDC3, + AXP809_DCDC4, + AXP809_DCDC5, + AXP809_DC1SW, + AXP809_DC5LDO, + AXP809_ALDO1, + AXP809_ALDO2, + AXP809_ALDO3, + AXP809_ELDO1, + AXP809_ELDO2, + AXP809_ELDO3, + AXP809_DLDO1, + AXP809_DLDO2, + AXP809_RTC_LDO, + AXP809_LDO_IO0, + AXP809_LDO_IO1, + AXP809_SW, + AXP809_REG_ID_MAX, +}; + /* IRQs */ enum { AXP152_IRQ_LDO0IN_CONNECT = 1, @@ -390,6 +414,41 @@ enum axp288_irqs { AXP288_IRQ_BC_USB_CHNG, }; +enum axp809_irqs { + AXP809_IRQ_ACIN_OVER_V = 1, + AXP809_IRQ_ACIN_PLUGIN, + AXP809_IRQ_ACIN_REMOVAL, + AXP809_IRQ_VBUS_OVER_V, + AXP809_IRQ_VBUS_PLUGIN, + AXP809_IRQ_VBUS_REMOVAL, + AXP809_IRQ_VBUS_V_LOW, + AXP809_IRQ_BATT_PLUGIN, + AXP809_IRQ_BATT_REMOVAL, + AXP809_IRQ_BATT_ENT_ACT_MODE, + AXP809_IRQ_BATT_EXIT_ACT_MODE, + AXP809_IRQ_CHARG, + AXP809_IRQ_CHARG_DONE, + AXP809_IRQ_BATT_CHG_TEMP_HIGH, + AXP809_IRQ_BATT_CHG_TEMP_HIGH_END, + AXP809_IRQ_BATT_CHG_TEMP_LOW, + AXP809_IRQ_BATT_CHG_TEMP_LOW_END, + AXP809_IRQ_BATT_ACT_TEMP_HIGH, + AXP809_IRQ_BATT_ACT_TEMP_HIGH_END, + AXP809_IRQ_BATT_ACT_TEMP_LOW, + AXP809_IRQ_BATT_ACT_TEMP_LOW_END, + AXP809_IRQ_DIE_TEMP_HIGH, + AXP809_IRQ_LOW_PWR_LVL1, + AXP809_IRQ_LOW_PWR_LVL2, + AXP809_IRQ_TIMER, + AXP809_IRQ_PEK_RIS_EDGE, + AXP809_IRQ_PEK_FAL_EDGE, + AXP809_IRQ_PEK_SHORT, + AXP809_IRQ_PEK_LONG, + AXP809_IRQ_PEK_OVER_OFF, + AXP809_IRQ_GPIO1_INPUT, + AXP809_IRQ_GPIO0_INPUT, +}; + #define AXP288_TS_ADC_H 0x58 #define AXP288_TS_ADC_L 0x59 #define AXP288_GP_ADC_H 0x5a From bd425113a186f6dc104e07cd501916dc51f25e6a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 29 Mar 2016 17:22:25 +0800 Subject: [PATCH 11/73] mfd: axp20x: Add bindings for AXP809 PMIC This patch adds the basic and regulator bindings for the X-Powers AXP809 PMIC. Also update the DC-DC converter operating frequency for AXP22X/AXP80X. Signed-off-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/axp20x.txt | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt index fd39fa54571b..d20b1034e967 100644 --- a/Documentation/devicetree/bindings/mfd/axp20x.txt +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt @@ -6,10 +6,11 @@ axp202 (X-Powers) axp209 (X-Powers) axp221 (X-Powers) axp223 (X-Powers) +axp809 (X-Powers) Required properties: - compatible: "x-powers,axp152", "x-powers,axp202", "x-powers,axp209", - "x-powers,axp221", "x-powers,axp223" + "x-powers,axp221", "x-powers,axp223", "x-powers,axp809" - reg: The I2C slave address or RSB hardware address for the AXP chip - interrupt-parent: The parent interrupt controller - interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin @@ -18,7 +19,9 @@ Required properties: Optional properties: - x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz - (range: 750-1875). Default: 1.5MHz + AXP152/20X: range: 750-1875, Default: 1.5 MHz + AXP22X/80X: range: 1800-4050, Default: 3 MHz + - -supply: a phandle to the regulator supply node. May be omitted if inputs are unregulated, such as using the IPSOUT output from the PMIC. @@ -77,6 +80,30 @@ LDO_IO0 : LDO : ips-supply : GPIO 0 LDO_IO1 : LDO : ips-supply : GPIO 1 RTC_LDO : LDO : ips-supply : always on +AXP809 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC1 : DC-DC buck : vin1-supply +DCDC2 : DC-DC buck : vin2-supply +DCDC3 : DC-DC buck : vin3-supply +DCDC4 : DC-DC buck : vin4-supply +DCDC5 : DC-DC buck : vin5-supply +DC1SW : On/Off Switch : : DCDC1 secondary output +DC5LDO : LDO : : input from DCDC5 +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +DLDO1 : LDO : dldoin-supply : shared supply +DLDO2 : LDO : dldoin-supply : shared supply +ELDO1 : LDO : eldoin-supply : shared supply +ELDO2 : LDO : eldoin-supply : shared supply +ELDO3 : LDO : eldoin-supply : shared supply +LDO_IO0 : LDO : ips-supply : GPIO 0 +LDO_IO1 : LDO : ips-supply : GPIO 1 +RTC_LDO : LDO : ips-supply : always on +SW : On/Off Switch : swin-supply + Example: axp209: pmic@34 { From a8f447be8056d9ce17bf7757d6de79426700bb8b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:12:55 +0530 Subject: [PATCH 12/73] mfd: Add resource managed APIs for mfd_add_devices Add resource managed API devm_mfd_add_devices() for the mfd_add_devices(). This helps in reducing code in error path as it is not required to call mfd_remove_devices() explicitly to remove all child-devices. In some cases, it also helps not to implement .remove() callback which get called during driver unbind. Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/mfd/core.h | 4 ++++ 2 files changed, 42 insertions(+) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 409da01effcd..4b4c1d4f3280 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -334,6 +334,44 @@ void mfd_remove_devices(struct device *parent) } EXPORT_SYMBOL(mfd_remove_devices); +static void devm_mfd_dev_release(struct device *dev, void *res) +{ + mfd_remove_devices(dev); +} + +/** + * devm_mfd_add_devices - Resource managed version of mfd_add_devices() + * + * Returns 0 on success or an appropriate negative error number on failure. + * All child-devices of the MFD will automatically be removed when it gets + * unbinded. + */ +int devm_mfd_add_devices(struct device *dev, int id, + const struct mfd_cell *cells, int n_devs, + struct resource *mem_base, + int irq_base, struct irq_domain *domain) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_mfd_dev_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = mfd_add_devices(dev, id, cells, n_devs, mem_base, + irq_base, domain); + if (ret < 0) { + devres_free(ptr); + return ret; + } + + *ptr = dev; + devres_add(dev, ptr); + + return ret; +} +EXPORT_SYMBOL(devm_mfd_add_devices); + int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) { struct mfd_cell cell_entry; diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index bc6f7e00fb3d..4a0268afe546 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -131,4 +131,8 @@ static inline int mfd_add_hotplug_devices(struct device *parent, extern void mfd_remove_devices(struct device *parent); +extern int devm_mfd_add_devices(struct device *dev, int id, + const struct mfd_cell *cells, int n_devs, + struct resource *mem_base, + int irq_base, struct irq_domain *irq_domain); #endif From 3698283b101388cb9d992ae4d34329f005aa35e8 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:12:56 +0530 Subject: [PATCH 13/73] mfd: Add devm_mfd_add_devices() in list of managed interfaces Add devm wrappers for the mfd_add_devices() in the list of managed interfaces. Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- Documentation/driver-model/devres.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 73b98dfbcea4..7f8c416f3bcf 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -317,6 +317,9 @@ MEM devm_kvasprintf() devm_kzalloc() +MFD + devm_mfd_add_devices() + PCI pcim_enable_device() : after success, all PCI ops become managed pcim_pin_device() : keep PCI device enabled after release From f9932c6e66c17ca3d84a7c6424c844bea8003ffb Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:12:57 +0530 Subject: [PATCH 14/73] mfd: act8945a: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Wenyou Yang CC: Krzysztof Kozlowski Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/act8945a.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/mfd/act8945a.c b/drivers/mfd/act8945a.c index 525b546ba42f..10c6d2da8822 100644 --- a/drivers/mfd/act8945a.c +++ b/drivers/mfd/act8945a.c @@ -46,8 +46,9 @@ static int act8945a_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, regmap); - ret = mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE, act8945a_devs, - ARRAY_SIZE(act8945a_devs), NULL, 0, NULL); + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE, + act8945a_devs, ARRAY_SIZE(act8945a_devs), + NULL, 0, NULL); if (ret) { dev_err(&i2c->dev, "Failed to add sub devices\n"); return ret; @@ -56,13 +57,6 @@ static int act8945a_i2c_probe(struct i2c_client *i2c, return 0; } -static int act8945a_i2c_remove(struct i2c_client *i2c) -{ - mfd_remove_devices(&i2c->dev); - - return 0; -} - static const struct i2c_device_id act8945a_i2c_id[] = { { "act8945a", 0 }, {} @@ -81,7 +75,6 @@ static struct i2c_driver act8945a_i2c_driver = { .of_match_table = of_match_ptr(act8945a_of_match), }, .probe = act8945a_i2c_probe, - .remove = act8945a_i2c_remove, .id_table = act8945a_i2c_id, }; From 9c9983267deab5c268676d8ac15686923b6e5e19 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:12:58 +0530 Subject: [PATCH 15/73] mfd: as3711: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Guennadi Liakhovetski Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/as3711.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index 09e1483b99bc..67b12417585d 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -189,22 +189,14 @@ static int as3711_i2c_probe(struct i2c_client *client, as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 0; } - ret = mfd_add_devices(as3711->dev, -1, as3711_subdevs, - ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL); + ret = devm_mfd_add_devices(as3711->dev, -1, as3711_subdevs, + ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL); if (ret < 0) dev_err(&client->dev, "add mfd devices failed: %d\n", ret); return ret; } -static int as3711_i2c_remove(struct i2c_client *client) -{ - struct as3711 *as3711 = i2c_get_clientdata(client); - - mfd_remove_devices(as3711->dev); - return 0; -} - static const struct i2c_device_id as3711_i2c_id[] = { {.name = "as3711", .driver_data = 0}, {} @@ -218,7 +210,6 @@ static struct i2c_driver as3711_i2c_driver = { .of_match_table = of_match_ptr(as3711_of_match), }, .probe = as3711_i2c_probe, - .remove = as3711_i2c_remove, .id_table = as3711_i2c_id, }; From f32fb9a593704a32ddc395686fa00075d10df173 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:12:59 +0530 Subject: [PATCH 16/73] mfd: atmel-hlcdc: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. Signed-off-by: Laxman Dewangan Acked-by: Boris Brezillon Signed-off-by: Lee Jones --- drivers/mfd/atmel-hlcdc.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c index 06c205868573..eca7ea69b81c 100644 --- a/drivers/mfd/atmel-hlcdc.c +++ b/drivers/mfd/atmel-hlcdc.c @@ -128,16 +128,9 @@ static int atmel_hlcdc_probe(struct platform_device *pdev) dev_set_drvdata(dev, hlcdc); - return mfd_add_devices(dev, -1, atmel_hlcdc_cells, - ARRAY_SIZE(atmel_hlcdc_cells), - NULL, 0, NULL); -} - -static int atmel_hlcdc_remove(struct platform_device *pdev) -{ - mfd_remove_devices(&pdev->dev); - - return 0; + return devm_mfd_add_devices(dev, -1, atmel_hlcdc_cells, + ARRAY_SIZE(atmel_hlcdc_cells), + NULL, 0, NULL); } static const struct of_device_id atmel_hlcdc_match[] = { @@ -152,7 +145,6 @@ MODULE_DEVICE_TABLE(of, atmel_hlcdc_match); static struct platform_driver atmel_hlcdc_driver = { .probe = atmel_hlcdc_probe, - .remove = atmel_hlcdc_remove, .driver = { .name = "atmel-hlcdc", .of_match_table = atmel_hlcdc_match, From 9148f2c01827fe1c8c8d589ac54b0f459759d78b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:00 +0530 Subject: [PATCH 17/73] mfd: bcm590xx: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Matt Porter Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/bcm590xx.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index 320aaefee718..0d76d690176b 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -82,8 +82,8 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri, goto err; } - ret = mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs, - ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL); + ret = devm_mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs, + ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL); if (ret < 0) { dev_err(&i2c_pri->dev, "failed to add sub-devices: %d\n", ret); goto err; @@ -96,12 +96,6 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri, return ret; } -static int bcm590xx_i2c_remove(struct i2c_client *i2c) -{ - mfd_remove_devices(&i2c->dev); - return 0; -} - static const struct of_device_id bcm590xx_of_match[] = { { .compatible = "brcm,bcm59056" }, { } @@ -120,7 +114,6 @@ static struct i2c_driver bcm590xx_i2c_driver = { .of_match_table = of_match_ptr(bcm590xx_of_match), }, .probe = bcm590xx_i2c_probe, - .remove = bcm590xx_i2c_remove, .id_table = bcm590xx_i2c_id, }; module_i2c_driver(bcm590xx_i2c_driver); From 9c384b0268c69a36e6b5d9c6b336fb81a63d457e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:01 +0530 Subject: [PATCH 18/73] mfd: hi6421-pmic: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Guodong Xu Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/hi6421-pmic-core.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index f9ded45a992d..3fd703fe3aba 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -76,8 +76,8 @@ static int hi6421_pmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmic); - ret = mfd_add_devices(&pdev->dev, 0, hi6421_devs, - ARRAY_SIZE(hi6421_devs), NULL, 0, NULL); + 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); return ret; @@ -86,13 +86,6 @@ static int hi6421_pmic_probe(struct platform_device *pdev) return 0; } -static int hi6421_pmic_remove(struct platform_device *pdev) -{ - mfd_remove_devices(&pdev->dev); - - return 0; -} - static const struct of_device_id of_hi6421_pmic_match_tbl[] = { { .compatible = "hisilicon,hi6421-pmic", }, { }, @@ -105,7 +98,6 @@ static struct platform_driver hi6421_pmic_driver = { .of_match_table = of_hi6421_pmic_match_tbl, }, .probe = hi6421_pmic_probe, - .remove = hi6421_pmic_remove, }; module_platform_driver(hi6421_pmic_driver); From c5f244549425c83835759f2d338967d0e798fda3 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:02 +0530 Subject: [PATCH 19/73] mfd: lp3943: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Milo Kim Signed-off-by: Laxman Dewangan Acked-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/lp3943.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c index eecbb13de1bd..65a2a8f14e74 100644 --- a/drivers/mfd/lp3943.c +++ b/drivers/mfd/lp3943.c @@ -123,16 +123,9 @@ static int lp3943_probe(struct i2c_client *cl, const struct i2c_device_id *id) lp3943->mux_cfg = lp3943_mux_cfg; i2c_set_clientdata(cl, lp3943); - return mfd_add_devices(dev, -1, lp3943_devs, ARRAY_SIZE(lp3943_devs), - NULL, 0, NULL); -} - -static int lp3943_remove(struct i2c_client *cl) -{ - struct lp3943 *lp3943 = i2c_get_clientdata(cl); - - mfd_remove_devices(lp3943->dev); - return 0; + return devm_mfd_add_devices(dev, -1, lp3943_devs, + ARRAY_SIZE(lp3943_devs), + NULL, 0, NULL); } static const struct i2c_device_id lp3943_ids[] = { @@ -151,7 +144,6 @@ MODULE_DEVICE_TABLE(of, lp3943_of_match); static struct i2c_driver lp3943_driver = { .probe = lp3943_probe, - .remove = lp3943_remove, .driver = { .name = "lp3943", .of_match_table = of_match_ptr(lp3943_of_match), From 7990ad17a9debc2c91ffc1413d01450c982fcb8d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:03 +0530 Subject: [PATCH 20/73] mfd: menf21bmc: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. Signed-off-by: Laxman Dewangan Reviewed-by: Andreas Werner Signed-off-by: Lee Jones --- drivers/mfd/menf21bmc.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/menf21bmc.c b/drivers/mfd/menf21bmc.c index 1c274345820c..3ad2def947d8 100644 --- a/drivers/mfd/menf21bmc.c +++ b/drivers/mfd/menf21bmc.c @@ -96,8 +96,8 @@ menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids) return ret; } - ret = mfd_add_devices(&client->dev, 0, menf21bmc_cell, - ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL); + ret = devm_mfd_add_devices(&client->dev, 0, menf21bmc_cell, + ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL); if (ret < 0) { dev_err(&client->dev, "failed to add BMC sub-devices\n"); return ret; @@ -106,12 +106,6 @@ menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids) return 0; } -static int menf21bmc_remove(struct i2c_client *client) -{ - mfd_remove_devices(&client->dev); - return 0; -} - static const struct i2c_device_id menf21bmc_id_table[] = { { "menf21bmc" }, { } @@ -122,7 +116,6 @@ static struct i2c_driver menf21bmc_driver = { .driver.name = "menf21bmc", .id_table = menf21bmc_id_table, .probe = menf21bmc_probe, - .remove = menf21bmc_remove, }; module_i2c_driver(menf21bmc_driver); From 08e380a53a92a445bdfd98e09680237bf0c269aa Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:04 +0530 Subject: [PATCH 21/73] mfd: mt6397: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: John Crispin Signed-off-by: Laxman Dewangan Reviewed-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/mt6397-core.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 8e8d93249c09..5a3ffa391942 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -276,8 +276,9 @@ static int mt6397_probe(struct platform_device *pdev) pmic->int_con[1] = MT6323_INT_CON1; pmic->int_status[0] = MT6323_INT_STATUS0; pmic->int_status[1] = MT6323_INT_STATUS1; - ret = mfd_add_devices(&pdev->dev, -1, mt6323_devs, - ARRAY_SIZE(mt6323_devs), NULL, 0, NULL); + ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs, + ARRAY_SIZE(mt6323_devs), NULL, + 0, NULL); break; case MT6397_CID_CODE: @@ -286,8 +287,9 @@ static int mt6397_probe(struct platform_device *pdev) pmic->int_con[1] = MT6397_INT_CON1; pmic->int_status[0] = MT6397_INT_STATUS0; pmic->int_status[1] = MT6397_INT_STATUS1; - ret = mfd_add_devices(&pdev->dev, -1, mt6397_devs, - ARRAY_SIZE(mt6397_devs), NULL, 0, NULL); + ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs, + ARRAY_SIZE(mt6397_devs), NULL, + 0, NULL); break; default: @@ -312,13 +314,6 @@ static int mt6397_probe(struct platform_device *pdev) return ret; } -static int mt6397_remove(struct platform_device *pdev) -{ - mfd_remove_devices(&pdev->dev); - - return 0; -} - static const struct of_device_id mt6397_of_match[] = { { .compatible = "mediatek,mt6397" }, { .compatible = "mediatek,mt6323" }, @@ -334,7 +329,6 @@ MODULE_DEVICE_TABLE(platform, mt6397_id); static struct platform_driver mt6397_driver = { .probe = mt6397_probe, - .remove = mt6397_remove, .driver = { .name = "mt6397", .of_match_table = of_match_ptr(mt6397_of_match), From 7360544c2b91d5689b635b2117f5e85986cf529b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:05 +0530 Subject: [PATCH 22/73] mfd: rdc321x: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Florian Fainelli Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/rdc321x-southbridge.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 6575585f1d1f..2bd8c5b6d600 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -85,14 +85,10 @@ static int rdc321x_sb_probe(struct pci_dev *pdev, rdc321x_gpio_pdata.sb_pdev = pdev; rdc321x_wdt_pdata.sb_pdev = pdev; - return mfd_add_devices(&pdev->dev, -1, - rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), - NULL, 0, NULL); -} - -static void rdc321x_sb_remove(struct pci_dev *pdev) -{ - mfd_remove_devices(&pdev->dev); + return devm_mfd_add_devices(&pdev->dev, -1, + rdc321x_sb_cells, + ARRAY_SIZE(rdc321x_sb_cells), + NULL, 0, NULL); } static const struct pci_device_id rdc321x_sb_table[] = { @@ -105,7 +101,6 @@ static struct pci_driver rdc321x_sb_driver = { .name = "RDC321x Southbridge", .id_table = rdc321x_sb_table, .probe = rdc321x_sb_probe, - .remove = rdc321x_sb_remove, }; module_pci_driver(rdc321x_sb_driver); From d5623161accbc567452700add15d76fc092b07fe Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:06 +0530 Subject: [PATCH 23/73] mfd: rk808: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and remove the call of mfd_remove_devices() from .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Chris Zhong Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/rk808.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 4b1e4399754b..49d7f624fc94 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -213,9 +213,9 @@ static int rk808_probe(struct i2c_client *client, rk808->i2c = client; i2c_set_clientdata(client, rk808); - ret = mfd_add_devices(&client->dev, -1, - rk808s, ARRAY_SIZE(rk808s), - NULL, 0, regmap_irq_get_domain(rk808->irq_data)); + ret = devm_mfd_add_devices(&client->dev, -1, + rk808s, ARRAY_SIZE(rk808s), NULL, 0, + regmap_irq_get_domain(rk808->irq_data)); if (ret) { dev_err(&client->dev, "failed to add MFD devices %d\n", ret); goto err_irq; @@ -240,7 +240,6 @@ static int rk808_remove(struct i2c_client *client) struct rk808 *rk808 = i2c_get_clientdata(client); regmap_del_irq_chip(client->irq, rk808->irq_data); - mfd_remove_devices(&client->dev); pm_power_off = NULL; return 0; From f41206c9fd5c48becdb0f2f65328c5438f6ea34d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:07 +0530 Subject: [PATCH 24/73] mfd: rn5t618: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and remove the call of mfd_remove_devices() from .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Beniamino Galvani Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/rn5t618.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 666857192dbe..0ad51d792feb 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -78,8 +78,8 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c, return ret; } - ret = mfd_add_devices(&i2c->dev, -1, rn5t618_cells, - ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL); + ret = devm_mfd_add_devices(&i2c->dev, -1, rn5t618_cells, + ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL); if (ret) { dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret); return ret; @@ -102,7 +102,6 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c) pm_power_off = NULL; } - mfd_remove_devices(&i2c->dev); return 0; } From 6b719eba9f01cd65ede04e64f20f648f8dbe6359 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:08 +0530 Subject: [PATCH 25/73] mfd: rt5033: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Ingi Kim Signed-off-by: Laxman Dewangan Reviewed-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/rt5033.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c index 2b95485f0057..9bd089c56375 100644 --- a/drivers/mfd/rt5033.c +++ b/drivers/mfd/rt5033.c @@ -97,9 +97,9 @@ static int rt5033_i2c_probe(struct i2c_client *i2c, return ret; } - ret = mfd_add_devices(rt5033->dev, -1, rt5033_devs, - ARRAY_SIZE(rt5033_devs), NULL, 0, - regmap_irq_get_domain(rt5033->irq_data)); + ret = devm_mfd_add_devices(rt5033->dev, -1, rt5033_devs, + ARRAY_SIZE(rt5033_devs), NULL, 0, + regmap_irq_get_domain(rt5033->irq_data)); if (ret < 0) { dev_err(&i2c->dev, "Failed to add RT5033 child devices.\n"); return ret; @@ -110,13 +110,6 @@ static int rt5033_i2c_probe(struct i2c_client *i2c, return 0; } -static int rt5033_i2c_remove(struct i2c_client *i2c) -{ - mfd_remove_devices(&i2c->dev); - - return 0; -} - static const struct i2c_device_id rt5033_i2c_id[] = { { "rt5033", }, { } @@ -135,7 +128,6 @@ static struct i2c_driver rt5033_driver = { .of_match_table = of_match_ptr(rt5033_dt_match), }, .probe = rt5033_i2c_probe, - .remove = rt5033_i2c_remove, .id_table = rt5033_i2c_id, }; module_i2c_driver(rt5033_driver); From 69633beaebf345cde6672a9ac7679c88fc0c3245 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:09 +0530 Subject: [PATCH 26/73] mfd: sky81452: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Gyungoh Yoo Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/sky81452.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/sky81452.c b/drivers/mfd/sky81452.c index b0c9b0415650..30a2a677100f 100644 --- a/drivers/mfd/sky81452.c +++ b/drivers/mfd/sky81452.c @@ -64,19 +64,14 @@ static int sky81452_probe(struct i2c_client *client, cells[1].platform_data = pdata->regulator_init_data; cells[1].pdata_size = sizeof(*pdata->regulator_init_data); - ret = mfd_add_devices(dev, -1, cells, ARRAY_SIZE(cells), NULL, 0, NULL); + ret = devm_mfd_add_devices(dev, -1, cells, ARRAY_SIZE(cells), + NULL, 0, NULL); if (ret) dev_err(dev, "failed to add child devices. err=%d\n", ret); return ret; } -static int sky81452_remove(struct i2c_client *client) -{ - mfd_remove_devices(&client->dev); - return 0; -} - static const struct i2c_device_id sky81452_ids[] = { { "sky81452" }, { } @@ -97,7 +92,6 @@ static struct i2c_driver sky81452_driver = { .of_match_table = of_match_ptr(sky81452_of_match), }, .probe = sky81452_probe, - .remove = sky81452_remove, .id_table = sky81452_ids, }; From e253fb0472e7a892176c7a65cef61a6aa75f8d2e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:10 +0530 Subject: [PATCH 27/73] mfd: stw481x: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. Signed-off-by: Laxman Dewangan Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/stw481x.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/stw481x.c b/drivers/mfd/stw481x.c index ca613df36143..ab949eaca6ad 100644 --- a/drivers/mfd/stw481x.c +++ b/drivers/mfd/stw481x.c @@ -206,8 +206,8 @@ static int stw481x_probe(struct i2c_client *client, stw481x_cells[i].pdata_size = sizeof(*stw481x); } - ret = mfd_add_devices(&client->dev, 0, stw481x_cells, - ARRAY_SIZE(stw481x_cells), NULL, 0, NULL); + ret = devm_mfd_add_devices(&client->dev, 0, stw481x_cells, + ARRAY_SIZE(stw481x_cells), NULL, 0, NULL); if (ret) return ret; @@ -216,12 +216,6 @@ static int stw481x_probe(struct i2c_client *client, return ret; } -static int stw481x_remove(struct i2c_client *client) -{ - mfd_remove_devices(&client->dev); - return 0; -} - /* * This ID table is completely unused, as this is a pure * device-tree probed driver, but it has to be here due to @@ -246,7 +240,6 @@ static struct i2c_driver stw481x_driver = { .of_match_table = stw481x_match, }, .probe = stw481x_probe, - .remove = stw481x_remove, .id_table = stw481x_id, }; From 5635d994fe870a0de2614e83bbf2d70f506651eb Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:11 +0530 Subject: [PATCH 28/73] mfd: tps6507x: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Todd Fischer Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/tps6507x.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 1ab3dd6c8adf..40beb2f4350c 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -100,16 +100,8 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c, tps6507x->read_dev = tps6507x_i2c_read_device; tps6507x->write_dev = tps6507x_i2c_write_device; - return mfd_add_devices(tps6507x->dev, -1, tps6507x_devs, - ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL); -} - -static int tps6507x_i2c_remove(struct i2c_client *i2c) -{ - struct tps6507x_dev *tps6507x = i2c_get_clientdata(i2c); - - mfd_remove_devices(tps6507x->dev); - return 0; + return devm_mfd_add_devices(tps6507x->dev, -1, tps6507x_devs, + ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL); } static const struct i2c_device_id tps6507x_i2c_id[] = { @@ -132,7 +124,6 @@ static struct i2c_driver tps6507x_i2c_driver = { .of_match_table = of_match_ptr(tps6507x_of_match), }, .probe = tps6507x_i2c_probe, - .remove = tps6507x_i2c_remove, .id_table = tps6507x_i2c_id, }; From b89b6b6bcd570a0beb1fc6fb8d0ecc20316413ab Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:12 +0530 Subject: [PATCH 29/73] mfd: tps65217: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Tony Lindgren Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/tps65217.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index d32b54426b70..049a6fcac651 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -205,8 +205,8 @@ static int tps65217_probe(struct i2c_client *client, return ret; } - ret = mfd_add_devices(tps->dev, -1, tps65217s, - ARRAY_SIZE(tps65217s), NULL, 0, NULL); + ret = devm_mfd_add_devices(tps->dev, -1, tps65217s, + ARRAY_SIZE(tps65217s), NULL, 0, NULL); if (ret < 0) { dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret); return ret; @@ -235,15 +235,6 @@ static int tps65217_probe(struct i2c_client *client, return 0; } -static int tps65217_remove(struct i2c_client *client) -{ - struct tps65217 *tps = i2c_get_clientdata(client); - - mfd_remove_devices(tps->dev); - - return 0; -} - static const struct i2c_device_id tps65217_id_table[] = { {"tps65217", TPS65217}, { /* sentinel */ } @@ -257,7 +248,6 @@ static struct i2c_driver tps65217_driver = { }, .id_table = tps65217_id_table, .probe = tps65217_probe, - .remove = tps65217_remove, }; static int __init tps65217_init(void) From f3466e7764783ed4fae91ebe1653b0a08cca22bf Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:13 +0530 Subject: [PATCH 30/73] mfd: tps65910: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and remove the call of mfd_remove_devices() from .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Tony Lindgren Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/tps65910.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index f7ab115483a9..8086e5dae311 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -510,10 +510,10 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, pm_power_off = tps65910_power_off; } - ret = mfd_add_devices(tps65910->dev, -1, - tps65910s, ARRAY_SIZE(tps65910s), - NULL, 0, - regmap_irq_get_domain(tps65910->irq_data)); + ret = devm_mfd_add_devices(tps65910->dev, -1, + tps65910s, ARRAY_SIZE(tps65910s), + NULL, 0, + regmap_irq_get_domain(tps65910->irq_data)); if (ret < 0) { dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); tps65910_irq_exit(tps65910); @@ -528,7 +528,6 @@ static int tps65910_i2c_remove(struct i2c_client *i2c) struct tps65910 *tps65910 = i2c_get_clientdata(i2c); tps65910_irq_exit(tps65910); - mfd_remove_devices(tps65910->dev); return 0; } From 7825dc05601b38f99808830098fd4f512c876b4e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Apr 2016 00:13:14 +0530 Subject: [PATCH 31/73] mfd: wm8400: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. CC: Mark Brown Signed-off-by: Laxman Dewangan Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm8400-core.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 3bd44a45c378..9fd823049f90 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -70,7 +70,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400) .pdata_size = sizeof(*wm8400), }; - return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL); + return devm_mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL); } /* @@ -111,7 +111,7 @@ static int wm8400_init(struct wm8400 *wm8400, ret = wm8400_register_codec(wm8400); if (ret != 0) { dev_err(wm8400->dev, "Failed to register codec\n"); - goto err_children; + return ret; } if (pdata && pdata->platform_init) { @@ -119,21 +119,12 @@ static int wm8400_init(struct wm8400 *wm8400, if (ret != 0) { dev_err(wm8400->dev, "Platform init failed: %d\n", ret); - goto err_children; + return ret; } } else dev_warn(wm8400->dev, "No platform initialisation supplied\n"); return 0; - -err_children: - mfd_remove_devices(wm8400->dev); - return ret; -} - -static void wm8400_release(struct wm8400 *wm8400) -{ - mfd_remove_devices(wm8400->dev); } static const struct regmap_config wm8400_regmap_config = { @@ -176,15 +167,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, return wm8400_init(wm8400, dev_get_platdata(&i2c->dev)); } -static int wm8400_i2c_remove(struct i2c_client *i2c) -{ - struct wm8400 *wm8400 = i2c_get_clientdata(i2c); - - wm8400_release(wm8400); - - return 0; -} - static const struct i2c_device_id wm8400_i2c_id[] = { { "wm8400", 0 }, { } @@ -196,7 +178,6 @@ static struct i2c_driver wm8400_i2c_driver = { .name = "WM8400", }, .probe = wm8400_i2c_probe, - .remove = wm8400_i2c_remove, .id_table = wm8400_i2c_id, }; #endif From cbdd535d9481025a5a9020f9e9875b68ad86111c Mon Sep 17 00:00:00 2001 From: Chen Feng Date: Sun, 14 Feb 2016 14:29:19 +0800 Subject: [PATCH 32/73] mfd: hi655x: Add document for hi665x PMIC DT bindings for hisilicon HI655x PMIC chip. Signed-off-by: Chen Feng Signed-off-by: Fei Wang Signed-off-by: Xinwei Kong Reviewed-by: Haojian Zhuang Signed-off-by: Lee Jones --- .../bindings/mfd/hisilicon,hi655x.txt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi655x.txt diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi655x.txt b/Documentation/devicetree/bindings/mfd/hisilicon,hi655x.txt new file mode 100644 index 000000000000..05485699d70e --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi655x.txt @@ -0,0 +1,27 @@ +Hisilicon Hi655x Power Management Integrated Circuit (PMIC) + +The hardware layout for access PMIC Hi655x from AP SoC Hi6220. +Between PMIC Hi655x and Hi6220, the physical signal channel is SSI. +We can use memory-mapped I/O to communicate. + ++----------------+ +-------------+ +| | | | +| Hi6220 | SSI bus | Hi655x | +| |-------------| | +| |(REGMAP_MMIO)| | ++----------------+ +-------------+ + +Required properties: +- compatible: Should be "hisilicon,hi655x-pmic". +- reg: Base address of PMIC on Hi6220 SoC. +- interrupt-controller: Hi655x has internal IRQs (has own IRQ domain). +- pmic-gpios: The GPIO used by PMIC IRQ. + +Example: + pmic: pmic@f8000000 { + compatible = "hisilicon,hi655x-pmic"; + reg = <0x0 0xf8000000 0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + pmic-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + } From 082cc468385dbc7bbdc234bf6f2577e64fc00bbb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:01 +0200 Subject: [PATCH 33/73] mfd: asic3: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Cc: Paul Parsons Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/asic3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 4dca6bc61f5b..0413c8159551 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -446,7 +446,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip, unsigned long flags; struct asic3 *asic; - asic = container_of(chip, struct asic3, gpio); + asic = gpiochip_get_data(chip); gpio_base = ASIC3_GPIO_TO_BASE(offset); if (gpio_base > ASIC3_GPIO_D_BASE) { @@ -492,7 +492,7 @@ static int asic3_gpio_get(struct gpio_chip *chip, u32 mask = ASIC3_GPIO_TO_MASK(offset); struct asic3 *asic; - asic = container_of(chip, struct asic3, gpio); + asic = gpiochip_get_data(chip); gpio_base = ASIC3_GPIO_TO_BASE(offset); if (gpio_base > ASIC3_GPIO_D_BASE) { @@ -513,7 +513,7 @@ static void asic3_gpio_set(struct gpio_chip *chip, unsigned long flags; struct asic3 *asic; - asic = container_of(chip, struct asic3, gpio); + asic = gpiochip_get_data(chip); gpio_base = ASIC3_GPIO_TO_BASE(offset); if (gpio_base > ASIC3_GPIO_D_BASE) { @@ -540,7 +540,7 @@ static void asic3_gpio_set(struct gpio_chip *chip, static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - struct asic3 *asic = container_of(chip, struct asic3, gpio); + struct asic3 *asic = gpiochip_get_data(chip); return asic->irq_base + offset; } @@ -595,7 +595,7 @@ static __init int asic3_gpio_probe(struct platform_device *pdev, alt_reg[i]); } - return gpiochip_add(&asic->gpio); + return gpiochip_add_data(&asic->gpio, asic); } static int asic3_gpio_remove(struct platform_device *pdev) From 4363765c851313d460db86f2d41d2eebca0d9c17 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:02 +0200 Subject: [PATCH 34/73] mfd: dm355evm_msp: Switch to gpiochip_add_data() We're planning to remove the gpiochip_add() function to swith to gpiochip_add_data() with NULL for data argument. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/dm355evm_msp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index ec4438ed2faf..d7d59f8d9d06 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -260,7 +260,7 @@ static int add_children(struct i2c_client *client) /* GPIO-ish stuff */ dm355evm_msp_gpio.parent = &client->dev; - status = gpiochip_add(&dm355evm_msp_gpio); + status = gpiochip_add_data(&dm355evm_msp_gpio, NULL); if (status < 0) return status; From 8d5f095fc5f7e36f40a80e87317828be249ee454 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:03 +0200 Subject: [PATCH 35/73] mfd: htc-egpio: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Acked-by: Philipp Zabel Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/htc-egpio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index c636b5f83cfb..513cfc5c8fb6 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -155,7 +155,7 @@ static int egpio_get(struct gpio_chip *chip, unsigned offset) pr_debug("egpio_get_value(%d)\n", chip->base + offset); - egpio = container_of(chip, struct egpio_chip, chip); + egpio = gpiochip_get_data(chip); ei = dev_get_drvdata(egpio->dev); bit = egpio_bit(ei, offset); reg = egpio->reg_start + egpio_pos(ei, offset); @@ -170,7 +170,7 @@ static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) { struct egpio_chip *egpio; - egpio = container_of(chip, struct egpio_chip, chip); + egpio = gpiochip_get_data(chip); return test_bit(offset, &egpio->is_out) ? -EINVAL : 0; } @@ -192,7 +192,7 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) pr_debug("egpio_set(%s, %d(%d), %d)\n", chip->label, offset, offset+chip->base, value); - egpio = container_of(chip, struct egpio_chip, chip); + egpio = gpiochip_get_data(chip); ei = dev_get_drvdata(egpio->dev); bit = egpio_bit(ei, offset); pos = egpio_pos(ei, offset); @@ -216,7 +216,7 @@ static int egpio_direction_output(struct gpio_chip *chip, { struct egpio_chip *egpio; - egpio = container_of(chip, struct egpio_chip, chip); + egpio = gpiochip_get_data(chip); if (test_bit(offset, &egpio->is_out)) { egpio_set(chip, offset, value); return 0; @@ -330,7 +330,7 @@ static int __init egpio_probe(struct platform_device *pdev) chip->base = pdata->chip[i].gpio_base; chip->ngpio = pdata->chip[i].num_gpios; - gpiochip_add(chip); + gpiochip_add_data(chip, &ei->chip[i]); } /* Set initial pin values */ From ed1c9b3c18e33a69da0a911eadf4948ea7e5b5b9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:04 +0200 Subject: [PATCH 36/73] mfd: htc-i2cpld: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/htc-i2cpld.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index bd6b96d07ab8..3f9eee5f8fb9 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -227,8 +227,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev) static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) { struct i2c_client *client; - struct htcpld_chip *chip_data = - container_of(chip, struct htcpld_chip, chip_out); + struct htcpld_chip *chip_data = gpiochip_get_data(chip); unsigned long flags; client = chip_data->client; @@ -257,14 +256,12 @@ static void htcpld_chip_set_ni(struct work_struct *work) static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) { - struct htcpld_chip *chip_data; + struct htcpld_chip *chip_data = gpiochip_get_data(chip); u8 cache; if (!strncmp(chip->label, "htcpld-out", 10)) { - chip_data = container_of(chip, struct htcpld_chip, chip_out); cache = chip_data->cache_out; } else if (!strncmp(chip->label, "htcpld-in", 9)) { - chip_data = container_of(chip, struct htcpld_chip, chip_in); cache = chip_data->cache_in; } else return -EINVAL; @@ -291,9 +288,7 @@ static int htcpld_direction_input(struct gpio_chip *chip, static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) { - struct htcpld_chip *chip_data; - - chip_data = container_of(chip, struct htcpld_chip, chip_in); + struct htcpld_chip *chip_data = gpiochip_get_data(chip); if (offset < chip_data->nirqs) return chip_data->irq_start + offset; @@ -451,14 +446,14 @@ static int htcpld_register_chip_gpio( gpio_chip->ngpio = plat_chip_data->num_gpios; /* Add the GPIO chips */ - ret = gpiochip_add(&(chip->chip_out)); + ret = gpiochip_add_data(&(chip->chip_out), chip); if (ret) { dev_warn(dev, "Unable to register output GPIOs for 0x%x: %d\n", plat_chip_data->addr, ret); return ret; } - ret = gpiochip_add(&(chip->chip_in)); + ret = gpiochip_add_data(&(chip->chip_in), chip); if (ret) { dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n", plat_chip_data->addr, ret); From 3a504105f0e4cf32464d596f3b30d23dbfd76520 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:05 +0200 Subject: [PATCH 37/73] mfd: sm501: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Cc: Ben Dooks Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/sm501.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index c646784c5a7d..65cd0d2a822a 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -879,11 +879,6 @@ static int sm501_register_display(struct sm501_devdata *sm, #ifdef CONFIG_MFD_SM501_GPIO -static inline struct sm501_gpio_chip *to_sm501_gpio(struct gpio_chip *gc) -{ - return container_of(gc, struct sm501_gpio_chip, gpio); -} - static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio) { return container_of(gpio, struct sm501_devdata, gpio); @@ -892,7 +887,7 @@ static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio) static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip); + struct sm501_gpio_chip *smgpio = gpiochip_get_data(chip); unsigned long result; result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW); @@ -923,7 +918,7 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip, static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct sm501_gpio_chip *smchip = to_sm501_gpio(chip); + struct sm501_gpio_chip *smchip = gpiochip_get_data(chip); struct sm501_gpio *smgpio = smchip->ourgpio; unsigned long bit = 1 << offset; void __iomem *regs = smchip->regbase; @@ -948,7 +943,7 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) { - struct sm501_gpio_chip *smchip = to_sm501_gpio(chip); + struct sm501_gpio_chip *smchip = gpiochip_get_data(chip); struct sm501_gpio *smgpio = smchip->ourgpio; void __iomem *regs = smchip->regbase; unsigned long bit = 1 << offset; @@ -974,7 +969,7 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) static int sm501_gpio_output(struct gpio_chip *chip, unsigned offset, int value) { - struct sm501_gpio_chip *smchip = to_sm501_gpio(chip); + struct sm501_gpio_chip *smchip = gpiochip_get_data(chip); struct sm501_gpio *smgpio = smchip->ourgpio; unsigned long bit = 1 << offset; void __iomem *regs = smchip->regbase; @@ -1039,7 +1034,7 @@ static int sm501_gpio_register_chip(struct sm501_devdata *sm, gchip->base = base; chip->ourgpio = gpio; - return gpiochip_add(gchip); + return gpiochip_add_data(gchip, chip); } static int sm501_register_gpio(struct sm501_devdata *sm) From 4e125f62b73dffde17f4c53155654623ab2a9855 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:06 +0200 Subject: [PATCH 38/73] mfd: tc6393xb: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Cc: Dmitry Baryshkov Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/tc6393xb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 1ecbfa40d1b3..d42d322ac7ca 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #define SCR_REVID 0x08 /* b Revision ID */ @@ -434,7 +434,7 @@ static struct mfd_cell tc6393xb_cells[] = { static int tc6393xb_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); + struct tc6393xb *tc6393xb = gpiochip_get_data(chip); /* XXX: does dsr also represent inputs? */ return !!(tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) @@ -444,7 +444,7 @@ static int tc6393xb_gpio_get(struct gpio_chip *chip, static void __tc6393xb_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); + struct tc6393xb *tc6393xb = gpiochip_get_data(chip); u8 dsr; dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); @@ -459,7 +459,7 @@ static void __tc6393xb_gpio_set(struct gpio_chip *chip, static void tc6393xb_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); + struct tc6393xb *tc6393xb = gpiochip_get_data(chip); unsigned long flags; spin_lock_irqsave(&tc6393xb->lock, flags); @@ -472,7 +472,7 @@ static void tc6393xb_gpio_set(struct gpio_chip *chip, static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); + struct tc6393xb *tc6393xb = gpiochip_get_data(chip); unsigned long flags; u8 doecr; @@ -490,7 +490,7 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { - struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); + struct tc6393xb *tc6393xb = gpiochip_get_data(chip); unsigned long flags; u8 doecr; @@ -517,7 +517,7 @@ static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input; tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output; - return gpiochip_add(&tc6393xb->gpio); + return gpiochip_add_data(&tc6393xb->gpio, tc6393xb); } /*--------------------------------------------------------------------------*/ From 22e5e747e71f19ac3af60ce648f4c02c63ed3cc1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:07 +0200 Subject: [PATCH 39/73] mfd: tps65010: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/tps65010.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 495e4518fc29..d829a6131f09 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -34,7 +34,7 @@ #include -#include +#include /*-------------------------------------------------------------------------*/ @@ -477,7 +477,7 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value) if (offset < 4) { struct tps65010 *tps; - tps = container_of(chip, struct tps65010, chip); + tps = gpiochip_get_data(chip); if (!(tps->outmask & (1 << offset))) return -EINVAL; tps65010_set_gpio_out_value(offset + 1, value); @@ -494,7 +494,7 @@ static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset) int value; struct tps65010 *tps; - tps = container_of(chip, struct tps65010, chip); + tps = gpiochip_get_data(chip); if (offset < 4) { value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO); @@ -651,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client, tps->chip.ngpio = 7; tps->chip.can_sleep = 1; - status = gpiochip_add(&tps->chip); + status = gpiochip_add_data(&tps->chip, tps); if (status < 0) dev_err(&client->dev, "can't add gpiochip, err %d\n", status); From 7d94352eba4f943734c19d172a834d0b2affec09 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:08 +0200 Subject: [PATCH 40/73] mfd: ucb1x00: Use gpiochip data pointer This makes the driver use the data pointer added to the gpio_chip to store a pointer to the state container instead of relying on container_of(). Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ucb1x00-core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index bcafe1ecd71c..9ab9ec47ea75 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include static DEFINE_MUTEX(ucb1x00_mutex); static LIST_HEAD(ucb1x00_drivers); @@ -109,7 +109,7 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + struct ucb1x00 *ucb = gpiochip_get_data(chip); unsigned long flags; spin_lock_irqsave(&ucb->io_lock, flags); @@ -126,7 +126,7 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + struct ucb1x00 *ucb = gpiochip_get_data(chip); unsigned val; ucb1x00_enable(ucb); @@ -138,7 +138,7 @@ static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + struct ucb1x00 *ucb = gpiochip_get_data(chip); unsigned long flags; spin_lock_irqsave(&ucb->io_lock, flags); @@ -154,7 +154,7 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset , int value) { - struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + struct ucb1x00 *ucb = gpiochip_get_data(chip); unsigned long flags; unsigned old, mask = 1 << offset; @@ -181,7 +181,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset) { - struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + struct ucb1x00 *ucb = gpiochip_get_data(chip); return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO; } @@ -579,7 +579,7 @@ static int ucb1x00_probe(struct mcp *mcp) ucb->gpio.direction_input = ucb1x00_gpio_direction_input; ucb->gpio.direction_output = ucb1x00_gpio_direction_output; ucb->gpio.to_irq = ucb1x00_to_irq; - ret = gpiochip_add(&ucb->gpio); + ret = gpiochip_add_data(&ucb->gpio, ucb); if (ret) goto err_gpio_add; } else From 7ad073695dff7b1fc2a6ef2e8112d96a76fc8dc4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2016 10:48:09 +0200 Subject: [PATCH 41/73] mfd: vexpress-sysreg: Switch to gpiochip_add_data() We're planning to remove the gpiochip_add() function to swith to gpiochip_add_data() with NULL for data argument. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/vexpress-sysreg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 855c0204f09a..201a3ea2a9d3 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -202,7 +202,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI, NULL, NULL, NULL, NULL, 0); mmc_gpio_chip->ngpio = 2; - gpiochip_add(mmc_gpio_chip); + gpiochip_add_data(mmc_gpio_chip, NULL); return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, vexpress_sysreg_cells, From 630fd98c0a7fcba67d4b33440793b0c9bd1fb440 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Apr 2016 11:04:51 +0900 Subject: [PATCH 42/73] mfd: max77686/max77693: Fix misspelled Samsung address Correct smasung.com into samsung.com. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max77686.c | 2 +- drivers/mfd/max77693.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index c1aff46e89d9..0aa33d4ee165 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -2,7 +2,7 @@ * max77686.c - mfd core driver for the Maxim 77686/802 * * Copyright (C) 2012 Samsung Electronics - * Chiwoong Byun + * Chiwoong Byun * Jonghwa Lee * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 78e501feb96c..662ae0d9e334 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -2,7 +2,7 @@ * max77693.c - mfd core driver for the MAX 77693 * * Copyright (C) 2012 Samsung Electronics - * SangYoung Son + * SangYoung Son * * This program is not provided / owned by Maxim Integrated Products. * From 8a0aee4a7c8500278495012d8f4b653033df83a3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 4 Apr 2016 18:46:02 -0400 Subject: [PATCH 43/73] mfd: max77686: Use module_i2c_driver() instead of subsys initcall The driver's init and exit function don't do anything besides adding and deleting the I2C driver so the module_i2c_driver() macro could be used. Currently is not being used because the driver is initialized at subsys initcall level, claiming that this is done to allow consumers devices to use the resources provided by this driver. But dependencies are in DT so manual ordering of init calls is not necessary any more. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Signed-off-by: Lee Jones --- drivers/mfd/max77686.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 0aa33d4ee165..7a0457e1771b 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -321,18 +321,7 @@ static struct i2c_driver max77686_i2c_driver = { .id_table = max77686_i2c_id, }; -static int __init max77686_i2c_init(void) -{ - return i2c_add_driver(&max77686_i2c_driver); -} -/* init early so consumer devices can complete system boot */ -subsys_initcall(max77686_i2c_init); - -static void __exit max77686_i2c_exit(void) -{ - i2c_del_driver(&max77686_i2c_driver); -} -module_exit(max77686_i2c_exit); +module_i2c_driver(max77686_i2c_driver); MODULE_DESCRIPTION("MAXIM 77686/802 multi-function core driver"); MODULE_AUTHOR("Chiwoong Byun "); From ba5776ab6f09800dd9ba8442185139661e065529 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 11 Apr 2016 10:27:32 -0700 Subject: [PATCH 44/73] mfd: cros_ec: Allow building for ARM64 There are platforms using the ChromeOS embeded controller on ARM64 now, so let's allow using this driver (without having to use COMPILE_TEST). Signed-off-by: Brian Norris Reviewed-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aa1e7c3f82ee..cf7cbba61971 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -134,7 +134,7 @@ config MFD_CROS_EC select MFD_CORE select CHROME_PLATFORMS select CROS_EC_PROTO - depends on X86 || ARM || COMPILE_TEST + depends on X86 || ARM || ARM64 || COMPILE_TEST help If you say Y here you get support for the ChromeOS Embedded Controller (EC) providing keyboard, battery and power services. From 1387ff53568ba409eef072087fa02359b3a3551b Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Fri, 15 Apr 2016 16:30:29 +0800 Subject: [PATCH 45/73] mfd: mt6397: IRQ domain should initialize before mfd_add_devices() Some sub driver like RTC module need irq domain from parent to create irq mapping when driver initialize. so move mt6397_irq_init() before mfd_add_devices(). Acked-by: John Crispin Signed-off-by: Henry Chen Signed-off-by: Lee Jones --- drivers/mfd/mt6397-core.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 5a3ffa391942..e14d8b058f0c 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -267,15 +267,23 @@ static int mt6397_probe(struct platform_device *pdev) ret = regmap_read(pmic->regmap, MT6397_CID, &id); if (ret) { dev_err(pmic->dev, "Failed to read chip id: %d\n", ret); - goto fail_irq; + return ret; } + pmic->irq = platform_get_irq(pdev, 0); + if (pmic->irq <= 0) + return pmic->irq; + switch (id & 0xff) { case MT6323_CID_CODE: pmic->int_con[0] = MT6323_INT_CON0; pmic->int_con[1] = MT6323_INT_CON1; pmic->int_status[0] = MT6323_INT_STATUS0; pmic->int_status[1] = MT6323_INT_STATUS1; + ret = mt6397_irq_init(pmic); + if (ret) + return ret; + ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs, ARRAY_SIZE(mt6323_devs), NULL, 0, NULL); @@ -287,6 +295,10 @@ static int mt6397_probe(struct platform_device *pdev) pmic->int_con[1] = MT6397_INT_CON1; pmic->int_status[0] = MT6397_INT_STATUS0; pmic->int_status[1] = MT6397_INT_STATUS1; + ret = mt6397_irq_init(pmic); + if (ret) + return ret; + ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs, ARRAY_SIZE(mt6397_devs), NULL, 0, NULL); @@ -298,14 +310,6 @@ static int mt6397_probe(struct platform_device *pdev) break; } - pmic->irq = platform_get_irq(pdev, 0); - if (pmic->irq > 0) { - ret = mt6397_irq_init(pmic); - if (ret) - return ret; - } - -fail_irq: if (ret) { irq_domain_remove(pmic->irq_domain); dev_err(&pdev->dev, "failed to add child devices: %d\n", ret); From f83c218c1705a0d38fb9791bdee268c4092a37cb Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 15 Apr 2016 13:18:47 +0100 Subject: [PATCH 46/73] mfd: arizona: Update device ordering to allow clean driver removal Since this commit: commit b9a8a271c38f ("mfd: make mfd_remove_devices() iterate in reverse order") The order in which the MFD children remove has been reversed, as our driver contains some dependencies between the devices we need to make some changes to ensure the driver unloads cleanly. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 5319f252790b..bf2717967597 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -908,12 +908,12 @@ static const char * const wm5102_supplies[] = { static const struct mfd_cell wm5102_devs[] = { { .name = "arizona-micsupp" }, + { .name = "arizona-gpio" }, { .name = "arizona-extcon", .parent_supplies = wm5102_supplies, .num_parent_supplies = 1, /* We only need MICVDD */ }, - { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -925,12 +925,12 @@ static const struct mfd_cell wm5102_devs[] = { static const struct mfd_cell wm5110_devs[] = { { .name = "arizona-micsupp" }, + { .name = "arizona-gpio" }, { .name = "arizona-extcon", .parent_supplies = wm5102_supplies, .num_parent_supplies = 1, /* We only need MICVDD */ }, - { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -966,12 +966,12 @@ static const char * const wm8997_supplies[] = { static const struct mfd_cell wm8997_devs[] = { { .name = "arizona-micsupp" }, + { .name = "arizona-gpio" }, { .name = "arizona-extcon", .parent_supplies = wm8997_supplies, .num_parent_supplies = 1, /* We only need MICVDD */ }, - { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -982,12 +982,13 @@ static const struct mfd_cell wm8997_devs[] = { }; static const struct mfd_cell wm8998_devs[] = { + { .name = "arizona-micsupp" }, + { .name = "arizona-gpio" }, { .name = "arizona-extcon", .parent_supplies = wm5102_supplies, .num_parent_supplies = 1, /* We only need MICVDD */ }, - { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -995,7 +996,6 @@ static const struct mfd_cell wm8998_devs[] = { .parent_supplies = wm5102_supplies, .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), }, - { .name = "arizona-micsupp" }, }; int arizona_dev_init(struct arizona *arizona) From 0e10d549f6eebd0a26bf075309b6fb947f4c1cb2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 15 Apr 2016 17:44:18 +0300 Subject: [PATCH 47/73] mfd: wm8400-core: Delete wm8400_reg_read() There was a static checker warning in wm8400_reg_read() because we were returning u16 and that can't hold the negative error codes. The function isn't used, so let's just delete it. Signed-off-by: Dan Carpenter Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm8400-core.c | 21 --------------------- include/linux/mfd/wm8400-private.h | 1 - 2 files changed, 22 deletions(-) diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 9fd823049f90..81667762c3ad 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -35,27 +35,6 @@ static bool wm8400_volatile(struct device *dev, unsigned int reg) } } -/** - * wm8400_reg_read - Single register read - * - * @wm8400: Pointer to wm8400 control structure - * @reg: Register to read - * - * @return Read value - */ -u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg) -{ - unsigned int val; - int ret; - - ret = regmap_read(wm8400->regmap, reg, &val); - if (ret < 0) - return ret; - - return val; -} -EXPORT_SYMBOL_GPL(wm8400_reg_read); - int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data) { return regmap_bulk_read(wm8400->regmap, reg, data, count); diff --git a/include/linux/mfd/wm8400-private.h b/include/linux/mfd/wm8400-private.h index 2de565b94d0c..4ee908f5b834 100644 --- a/include/linux/mfd/wm8400-private.h +++ b/include/linux/mfd/wm8400-private.h @@ -923,7 +923,6 @@ struct wm8400 { #define WM8400_LINE_CMP_VTHD_SHIFT 0 /* LINE_CMP_VTHD - [3:0] */ #define WM8400_LINE_CMP_VTHD_WIDTH 4 /* LINE_CMP_VTHD - [3:0] */ -u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg); int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data); static inline int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, From 41a3da2b8e1639d983192e3650670df4ecc94cf7 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 18 Apr 2016 15:14:56 +0300 Subject: [PATCH 48/73] mfd: intel-lpss: Save register context on suspend All configurations are lost and the registers will have default values when the hardware is suspended and resumed, so saving the private register space context on suspend, and restoring it on resume. Fixes: 4b45efe85263 (mfd: Add support for Intel Sunrisepoint LPSS devices) Cc: stable@vger.kernel.org # v4.3+ Signed-off-by: Heikki Krogerus Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 1bbbe877ba7e..807a3e3ec29a 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -34,6 +34,7 @@ #define LPSS_DEV_SIZE 0x200 #define LPSS_PRIV_OFFSET 0x200 #define LPSS_PRIV_SIZE 0x100 +#define LPSS_PRIV_REG_COUNT (LPSS_PRIV_SIZE / 4) #define LPSS_IDMA64_OFFSET 0x800 #define LPSS_IDMA64_SIZE 0x800 @@ -76,6 +77,7 @@ struct intel_lpss { struct mfd_cell *cell; struct device *dev; void __iomem *priv; + u32 priv_ctx[LPSS_PRIV_REG_COUNT]; int devid; u32 caps; u32 active_ltr; @@ -493,6 +495,16 @@ EXPORT_SYMBOL_GPL(intel_lpss_prepare); int intel_lpss_suspend(struct device *dev) { + struct intel_lpss *lpss = dev_get_drvdata(dev); + unsigned int i; + + /* Save device context */ + for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) + lpss->priv_ctx[i] = readl(lpss->priv + i * 4); + + /* Put the device into reset state */ + writel(0, lpss->priv + LPSS_PRIV_RESETS); + return 0; } EXPORT_SYMBOL_GPL(intel_lpss_suspend); @@ -500,8 +512,13 @@ EXPORT_SYMBOL_GPL(intel_lpss_suspend); int intel_lpss_resume(struct device *dev) { struct intel_lpss *lpss = dev_get_drvdata(dev); + unsigned int i; - intel_lpss_init_dev(lpss); + intel_lpss_deassert_reset(lpss); + + /* Restore device context */ + for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) + writel(lpss->priv_ctx[i], lpss->priv + i * 4); return 0; } From 0f7e70e7da0a09d9d0a814f17272ea7da7855f64 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 19 Apr 2016 18:20:49 -0700 Subject: [PATCH 49/73] mfd: intel-lpss: Remove CLK_IS_ROOT This flag is a no-op now (see commit 47b0eeb3dc8a "clk: Deprecate CLK_IS_ROOT", 2016-02-02) so remove it. Acked-by: Mika Westerberg Signed-off-by: Stephen Boyd Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 807a3e3ec29a..98e59809a831 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -338,8 +338,8 @@ static int intel_lpss_register_clock(struct intel_lpss *lpss) return 0; /* Root clock */ - clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, - CLK_IS_ROOT, lpss->info->clk_rate); + clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, 0, + lpss->info->clk_rate); if (IS_ERR(clk)) return PTR_ERR(clk); From 36a0c08848285bb12ed8b83f5eec4a92a5efadf9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 19 Apr 2016 18:19:20 -0700 Subject: [PATCH 50/73] mfd: intel_quark_i2c_gpio: Remove CLK_IS_ROOT This flag is a no-op now (see commit 47b0eeb3dc8a "clk: Deprecate CLK_IS_ROOT", 2016-02-02) so remove it. Acked-by: Andy Shevchenko Signed-off-by: Stephen Boyd Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 24c2d291b1dc..ce17ae8a81c9 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -130,7 +130,7 @@ static int intel_quark_register_i2c_clk(struct device *dev) i2c_clk = clk_register_fixed_rate(dev, INTEL_QUARK_I2C_CONTROLLER_CLK, NULL, - CLK_IS_ROOT, INTEL_QUARK_I2C_CLK_HZ); + 0, INTEL_QUARK_I2C_CLK_HZ); if (IS_ERR(i2c_clk)) return PTR_ERR(i2c_clk); From 38fc2eec95a750f2a69d82307ab721265e34939f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 20 Apr 2016 17:40:55 +0100 Subject: [PATCH 51/73] mfd: tps6105x: Remove linux/regulator/driver.h include This driver makes no use of linux/regulator/driver.h which should only be used by drivers implementing a regulator. Since it's unlikely to ever need anything from there remove the include. Signed-off-by: Mark Brown Signed-off-by: Lee Jones --- drivers/mfd/tps6105x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 51c54951c220..baa12ea666fb 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include From 32852bcab29d8d43c5d4ddeed9937817e8e8c990 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 20 Apr 2016 11:16:38 -0400 Subject: [PATCH 52/73] mfd: twl6040: Check clk_prepare_enable() return value in twl6040_power() The clk_prepare_enable() function can fail so check the return value and propagate the error in case of a failure. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 08a693cd38cc..85cc32a2e0e0 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -291,7 +291,11 @@ int twl6040_power(struct twl6040 *twl6040, int on) if (twl6040->power_count++) goto out; - clk_prepare_enable(twl6040->clk32k); + ret = clk_prepare_enable(twl6040->clk32k); + if (ret) { + twl6040->power_count = 0; + goto out; + } /* Allow writes to the chip */ regcache_cache_only(twl6040->regmap, false); From d6441dc5ce2bc8b296a65952d840d2f16e37f974 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 20 Apr 2016 11:16:37 -0400 Subject: [PATCH 53/73] mfd: twl6040: Disable and unprepare clk32k in twl6040_power() error path The clk32k clock is prepared and enabled in twl6040_power() but the clock is left enabled in case of an error while it should be disable/unprepared. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 85cc32a2e0e0..852d5874aabb 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -304,6 +304,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) /* use automatic power-up sequence */ ret = twl6040_power_up_automatic(twl6040); if (ret) { + clk_disable_unprepare(twl6040->clk32k); twl6040->power_count = 0; goto out; } @@ -311,6 +312,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) /* use manual power-up sequence */ ret = twl6040_power_up_manual(twl6040); if (ret) { + clk_disable_unprepare(twl6040->clk32k); twl6040->power_count = 0; goto out; } From 5eb519f3f6df367d43ec0c6e063fd62943fe4dcf Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 20 Apr 2016 13:45:46 -0400 Subject: [PATCH 54/73] mfd: Use IS_ENABLED(CONFIG_FOO) instead of checking FOO || FOO_MODULE The IS_ENABLED() macro checks if a Kconfig symbol has been enabled either built-in or as a module, use that macro instead of open coding the same. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/dm355evm_msp.c | 8 ++++---- drivers/mfd/wm8400-core.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index d7d59f8d9d06..14661ec5ef7f 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -33,25 +33,25 @@ * This driver was tested with firmware revision A4. */ -#if defined(CONFIG_INPUT_DM355EVM) || defined(CONFIG_INPUT_DM355EVM_MODULE) +#if IS_ENABLED(CONFIG_INPUT_DM355EVM) #define msp_has_keyboard() true #else #define msp_has_keyboard() false #endif -#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +#if IS_ENABLED(CONFIG_LEDS_GPIO) #define msp_has_leds() true #else #define msp_has_leds() false #endif -#if defined(CONFIG_RTC_DRV_DM355EVM) || defined(CONFIG_RTC_DRV_DM355EVM_MODULE) +#if IS_ENABLED(CONFIG_RTC_DRV_DM355EVM) #define msp_has_rtc() true #else #define msp_has_rtc() false #endif -#if defined(CONFIG_VIDEO_TVP514X) || defined(CONFIG_VIDEO_TVP514X_MODULE) +#if IS_ENABLED(CONFIG_VIDEO_TVP514X) #define msp_has_tvp() true #else #define msp_has_tvp() false diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 81667762c3ad..8a98a2fc74e1 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -126,7 +126,7 @@ void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) } EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C) static int wm8400_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -165,7 +165,7 @@ static int __init wm8400_module_init(void) { int ret = -ENODEV; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&wm8400_i2c_driver); if (ret != 0) pr_err("Failed to register I2C driver: %d\n", ret); @@ -177,7 +177,7 @@ subsys_initcall(wm8400_module_init); static void __exit wm8400_module_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C) i2c_del_driver(&wm8400_i2c_driver); #endif } From 030ab2beb4cb045891395bb5e849cf583193b5fb Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:45:39 +0530 Subject: [PATCH 55/73] mfd: smsc-ece1099: Remove unnecessarily remove callback SMSC MFD driver does not add any MFD child devices via mfd_add_devices() and hence it is not required to call mfd_remove_devices() to remove MFD child devices. Remove the call of the API mfd_remove_devices() which will result as remove of .remove callback for driver. Signed-off-by: Laxman Dewangan Signed-off-by: Sourav Poddar Signed-off-by: Lee Jones --- drivers/mfd/smsc-ece1099.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c index a4c0df71c8b3..7f89e89b8a5e 100644 --- a/drivers/mfd/smsc-ece1099.c +++ b/drivers/mfd/smsc-ece1099.c @@ -80,15 +80,6 @@ static int smsc_i2c_probe(struct i2c_client *i2c, return ret; } -static int smsc_i2c_remove(struct i2c_client *i2c) -{ - struct smsc *smsc = i2c_get_clientdata(i2c); - - mfd_remove_devices(smsc->dev); - - return 0; -} - static const struct i2c_device_id smsc_i2c_id[] = { { "smscece1099", 0}, {}, @@ -100,7 +91,6 @@ static struct i2c_driver smsc_i2c_driver = { .name = "smsc", }, .probe = smsc_i2c_probe, - .remove = smsc_i2c_remove, .id_table = smsc_i2c_id, }; From 39ac9f48f63acefbcd0f2c6eece89915565d6a59 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 29 Mar 2016 17:22:24 +0800 Subject: [PATCH 56/73] MAINTAINERS: Add entry for X-Powers AXP family PMIC drivers Add an entry for X-Powers AXP family PMIC drivers and list myself as maintainer. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Lee Jones --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1c32f8a3d6c4..f4ba27328a39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12150,6 +12150,12 @@ F: include/linux/workqueue.h F: kernel/workqueue.c F: Documentation/workqueue.txt +X-POWERS MULTIFUNCTION PMIC DEVICE DRIVERS +M: Chen-Yu Tsai +L: linux-kernel@vger.kernel.org +S: Maintained +N: axp[128] + X.25 NETWORK LAYER M: Andrew Hendry L: linux-x25@vger.kernel.org From ae9810e275d5847ded7e1cbcf231c3fcf95b6e52 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 25 Apr 2016 13:06:32 -0400 Subject: [PATCH 57/73] mfd: twl4030-power: Remove driver path in file comment The driver's file path in the comment is wrong, so just remove it since these tends to get out of date and they serve very little purpose. Suggested-by: Lee Jones Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/twl4030-power.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 04b539850e72..1beb722f6080 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -1,5 +1,4 @@ /* - * linux/drivers/i2c/chips/twl4030-power.c * * Handle TWL4030 Power initialization * From 0bbfb87c567d982fd698b41e9fb68478727460f9 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:55:52 +0530 Subject: [PATCH 58/73] mfd: as3722: Use devm_mfd_add_devices and devm_regmap_add_irq_chip Use devm_mfd_add_devices() for adding MFD child devices and devm_regmap_add_irq_chip() for IRQ chip registration. This reduces the error code path and .remove callback for removing MFD child devices and deleting IRQ chip data. Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/as3722.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index e1f597f97f86..f87342c211bc 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -385,9 +385,10 @@ static int as3722_i2c_probe(struct i2c_client *i2c, return ret; irq_flags = as3722->irq_flags | IRQF_ONESHOT; - ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq, - irq_flags, -1, &as3722_irq_chip, - &as3722->irq_data); + ret = devm_regmap_add_irq_chip(as3722->dev, as3722->regmap, + as3722->chip_irq, + irq_flags, -1, &as3722_irq_chip, + &as3722->irq_data); if (ret < 0) { dev_err(as3722->dev, "Failed to add regmap irq: %d\n", ret); return ret; @@ -395,33 +396,20 @@ static int as3722_i2c_probe(struct i2c_client *i2c, ret = as3722_configure_pullups(as3722); if (ret < 0) - goto scrub; + return ret; - ret = mfd_add_devices(&i2c->dev, -1, as3722_devs, - ARRAY_SIZE(as3722_devs), NULL, 0, - regmap_irq_get_domain(as3722->irq_data)); + ret = devm_mfd_add_devices(&i2c->dev, -1, as3722_devs, + ARRAY_SIZE(as3722_devs), NULL, 0, + regmap_irq_get_domain(as3722->irq_data)); if (ret) { dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret); - goto scrub; + return ret; } device_init_wakeup(as3722->dev, true); dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n"); return 0; - -scrub: - regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data); - return ret; -} - -static int as3722_i2c_remove(struct i2c_client *i2c) -{ - struct as3722 *as3722 = i2c_get_clientdata(i2c); - - mfd_remove_devices(as3722->dev); - regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data); - return 0; } static int __maybe_unused as3722_i2c_suspend(struct device *dev) @@ -470,7 +458,6 @@ static struct i2c_driver as3722_i2c_driver = { .pm = &as3722_pm_ops, }, .probe = as3722_i2c_probe, - .remove = as3722_i2c_remove, .id_table = as3722_i2c_id, }; From 1a5422c9e56a20898a73da5726d935d5d8072f78 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:55:54 +0530 Subject: [PATCH 59/73] mfd: max77686: Use devm_mfd_add_devices and devm_regmap_add_irq_chip Use devm_mfd_add_devices() for adding MFD child devices and devm_regmap_add_irq_chip() for IRQ chip registration. This reduces the error code path and .remove callback for removing MFD child devices and deleting IRQ chip data. Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max77686.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 7a0457e1771b..7b68ed72e9cb 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -230,37 +230,23 @@ static int max77686_i2c_probe(struct i2c_client *i2c, return -ENODEV; } - ret = regmap_add_irq_chip(max77686->regmap, max77686->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT | - IRQF_SHARED, 0, irq_chip, - &max77686->irq_data); + ret = devm_regmap_add_irq_chip(&i2c->dev, max77686->regmap, + max77686->irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT | + IRQF_SHARED, 0, irq_chip, + &max77686->irq_data); if (ret < 0) { dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret); return ret; } - ret = mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL, 0, NULL); + ret = devm_mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL, + 0, NULL); if (ret < 0) { dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); - goto err_del_irqc; + return ret; } - return 0; - -err_del_irqc: - regmap_del_irq_chip(max77686->irq, max77686->irq_data); - - return ret; -} - -static int max77686_i2c_remove(struct i2c_client *i2c) -{ - struct max77686_dev *max77686 = i2c_get_clientdata(i2c); - - mfd_remove_devices(max77686->dev); - - regmap_del_irq_chip(max77686->irq, max77686->irq_data); - return 0; } @@ -317,7 +303,6 @@ static struct i2c_driver max77686_i2c_driver = { .of_match_table = of_match_ptr(max77686_pmic_dt_match), }, .probe = max77686_i2c_probe, - .remove = max77686_i2c_remove, .id_table = max77686_i2c_id, }; From b36c82724fa10da7cc73693c6c2c3ab9a6c8034b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:55:55 +0530 Subject: [PATCH 60/73] mfd: rc5t583: Use devm_mfd_add_devices and devm_request_threaded_irq Use devm_mfd_add_devices() for adding MFD child devices and devm_request_threaded_irq() for IRQ registration. This reduces the need of remove callback for removing MFD child devices and unregistering IRQ. Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/rc5t583-irq.c | 11 ++--------- drivers/mfd/rc5t583.c | 24 +++--------------------- 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c index 3f8812daa304..f8dde59ea6af 100644 --- a/drivers/mfd/rc5t583-irq.c +++ b/drivers/mfd/rc5t583-irq.c @@ -389,17 +389,10 @@ int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base) irq_clear_status_flags(__irq, IRQ_NOREQUEST); } - ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT, - "rc5t583", rc5t583); + ret = devm_request_threaded_irq(rc5t583->dev, irq, NULL, rc5t583_irq, + IRQF_ONESHOT, "rc5t583", rc5t583); if (ret < 0) dev_err(rc5t583->dev, "Error in registering interrupt error: %d\n", ret); return ret; } - -int rc5t583_irq_exit(struct rc5t583 *rc5t583) -{ - if (rc5t583->chip_irq) - free_irq(rc5t583->chip_irq, rc5t583); - return 0; -} diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index fc2b2d93f354..d12243d5ecb8 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -252,7 +252,6 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c, struct rc5t583 *rc5t583; struct rc5t583_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret; - bool irq_init_success = false; if (!pdata) { dev_err(&i2c->dev, "Err: Platform data not found\n"); @@ -284,32 +283,16 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c, /* Still continue with warning, if irq init fails */ if (ret) dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret); - else - irq_init_success = true; } - ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs, - ARRAY_SIZE(rc5t583_subdevs), NULL, 0, NULL); + ret = devm_mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs, + ARRAY_SIZE(rc5t583_subdevs), NULL, 0, NULL); if (ret) { dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret); - goto err_add_devs; + return ret; } return 0; - -err_add_devs: - if (irq_init_success) - rc5t583_irq_exit(rc5t583); - return ret; -} - -static int rc5t583_i2c_remove(struct i2c_client *i2c) -{ - struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c); - - mfd_remove_devices(rc5t583->dev); - rc5t583_irq_exit(rc5t583); - return 0; } static const struct i2c_device_id rc5t583_i2c_id[] = { @@ -324,7 +307,6 @@ static struct i2c_driver rc5t583_i2c_driver = { .name = "rc5t583", }, .probe = rc5t583_i2c_probe, - .remove = rc5t583_i2c_remove, .id_table = rc5t583_i2c_id, }; From 3dc6f4aaafbe9e745fd1183b7a7a91aeeae99fcd Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:55:56 +0530 Subject: [PATCH 61/73] mfd: sec: Use devm_mfd_add_devices and devm_regmap_add_irq_chip Use devm_mfd_add_devices() for adding MFD child devices and devm_regmap_add_irq_chip() for IRQ chip registration. This reduces the error code path and .remove callback for removing MFD child devices and deleting IRQ chip data. Signed-off-by: Laxman Dewangan Tested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 20 +++----------------- drivers/mfd/sec-irq.c | 14 +++++--------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 400e1d7d8d08..ca6b80d08ffc 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -481,29 +481,16 @@ static int sec_pmic_probe(struct i2c_client *i2c, /* If this happens the probe function is problem */ BUG(); } - ret = mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL, - 0, NULL); + ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, + NULL, 0, NULL); if (ret) - goto err_mfd; + return ret; device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); sec_pmic_configure(sec_pmic); sec_pmic_dump_rev(sec_pmic); return ret; - -err_mfd: - sec_irq_exit(sec_pmic); - return ret; -} - -static int sec_pmic_remove(struct i2c_client *i2c) -{ - struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - - mfd_remove_devices(sec_pmic->dev); - sec_irq_exit(sec_pmic); - return 0; } static void sec_pmic_shutdown(struct i2c_client *i2c) @@ -583,7 +570,6 @@ static struct i2c_driver sec_pmic_driver = { .of_match_table = of_match_ptr(sec_dt_match), }, .probe = sec_pmic_probe, - .remove = sec_pmic_remove, .shutdown = sec_pmic_shutdown, .id_table = sec_pmic_id, }; diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index d77de431cc50..5eb59c233d52 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -483,10 +483,11 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) return -EINVAL; } - ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - sec_pmic->irq_base, sec_irq_chip, - &sec_pmic->irq_data); + ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, + sec_pmic->irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + sec_pmic->irq_base, sec_irq_chip, + &sec_pmic->irq_data); if (ret != 0) { dev_err(sec_pmic->dev, "Failed to register IRQ chip: %d\n", ret); return ret; @@ -500,8 +501,3 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) return 0; } - -void sec_irq_exit(struct sec_pmic_dev *sec_pmic) -{ - regmap_del_irq_chip(sec_pmic->irq, sec_pmic->irq_data); -} From 6167c5bcef722819ff536dc63ec89825001161ed Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:55:57 +0530 Subject: [PATCH 62/73] mfd: tps65910: Use devm_mfd_add_devices and devm_regmap_add_irq_chip Use devm_mfd_add_devices() for adding MFD child devices and devm_regmap_add_irq_chip() for IRQ chip registration. This reduces the error code path and .remove callback for removing MFD child devices and deleting IRQ chip data. Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/tps65910.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 8086e5dae311..11cab1582f2f 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -252,9 +252,10 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq, } tps65910->chip_irq = irq; - ret = regmap_add_irq_chip(tps65910->regmap, tps65910->chip_irq, - IRQF_ONESHOT, pdata->irq_base, - tps6591x_irqs_chip, &tps65910->irq_data); + ret = devm_regmap_add_irq_chip(tps65910->dev, tps65910->regmap, + tps65910->chip_irq, + IRQF_ONESHOT, pdata->irq_base, + tps6591x_irqs_chip, &tps65910->irq_data); if (ret < 0) { dev_warn(tps65910->dev, "Failed to add irq_chip %d\n", ret); tps65910->chip_irq = 0; @@ -262,13 +263,6 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq, return ret; } -static int tps65910_irq_exit(struct tps65910 *tps65910) -{ - if (tps65910->chip_irq > 0) - regmap_del_irq_chip(tps65910->chip_irq, tps65910->irq_data); - return 0; -} - static bool is_volatile_reg(struct device *dev, unsigned int reg) { struct tps65910 *tps65910 = dev_get_drvdata(dev); @@ -516,22 +510,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, regmap_irq_get_domain(tps65910->irq_data)); if (ret < 0) { dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); - tps65910_irq_exit(tps65910); return ret; } return ret; } -static int tps65910_i2c_remove(struct i2c_client *i2c) -{ - struct tps65910 *tps65910 = i2c_get_clientdata(i2c); - - tps65910_irq_exit(tps65910); - - return 0; -} - static const struct i2c_device_id tps65910_i2c_id[] = { { "tps65910", TPS65910 }, { "tps65911", TPS65911 }, @@ -546,7 +530,6 @@ static struct i2c_driver tps65910_i2c_driver = { .of_match_table = of_match_ptr(tps65910_of_match), }, .probe = tps65910_i2c_probe, - .remove = tps65910_i2c_remove, .id_table = tps65910_i2c_id, }; From 14856f75825f77b13564a8cc71deb21409671ab1 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Apr 2016 17:55:58 +0530 Subject: [PATCH 63/73] mfd: wl1273-core: Use devm_mfd_add_devices() for mfd_device registration Use devm_mfd_add_devices() for MFD devices registration and get rid of .remove callback to remove MFD child-devices. This is done by managed device framework. Signed-off-by: Laxman Dewangan Signed-off-by: Lee Jones --- drivers/mfd/wl1273-core.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index f7c52d901040..708046592b33 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -170,15 +170,6 @@ static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) return 0; } -static int wl1273_core_remove(struct i2c_client *client) -{ - dev_dbg(&client->dev, "%s\n", __func__); - - mfd_remove_devices(&client->dev); - - return 0; -} - static int wl1273_core_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -237,8 +228,8 @@ static int wl1273_core_probe(struct i2c_client *client, dev_dbg(&client->dev, "%s: number of children: %d.\n", __func__, children); - r = mfd_add_devices(&client->dev, -1, core->cells, - children, NULL, 0, NULL); + r = devm_mfd_add_devices(&client->dev, -1, core->cells, + children, NULL, 0, NULL); if (r) goto err; @@ -258,7 +249,6 @@ static struct i2c_driver wl1273_core_driver = { }, .probe = wl1273_core_probe, .id_table = wl1273_driver_id_table, - .remove = wl1273_core_remove, }; static int __init wl1273_core_init(void) From 36e6d081cfb2cb64e6d8e5121cffb1e62f894d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Apr 2016 22:38:55 +0300 Subject: [PATCH 64/73] mfd: intel_soc_pmic_core: Terminate panel control GPIO lookup table correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPIO lookup tables are supposed to be zero terminated. Let's do that and avoid accidentally walking off the end. Cc: stable@vger.kernel.org Fixes: 61dd2ca2d44e ("mfd: intel_soc_pmic_core: Add lookup table for Panel Control as GPIO signal") Signed-off-by: Ville Syrjälä Acked-by: Linus Walleij Acked-by: Daniel Vetter Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index d9e15cf7c6c8..12d6ebb4ae5d 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -35,6 +35,7 @@ static struct gpiod_lookup_table panel_gpio_table = { .table = { /* Panel EN/DISABLE */ GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH), + { }, }, }; From cd7cf27b8f49505e7419b48e8b51962663819922 Mon Sep 17 00:00:00 2001 From: Michael Haas Date: Fri, 6 May 2016 07:19:49 +0200 Subject: [PATCH 65/73] mfd: axp20x: Add a cell for the ac power_supply part of the axp20x PMICs As a counterpart to the usb power_supply cell, this commit adds an AC power_supply cell to the axp20x driver. Still missing are the RTC backup battery and the main battery charger cells. Signed-off-by: Michael Haas Acked-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 1ce923277cc8..e4e32978c377 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -130,6 +130,12 @@ static struct resource axp152_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; +static struct resource axp20x_ac_power_supply_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"), + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"), + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_OVER_V, "ACIN_OVER_V"), +}; + static struct resource axp20x_pek_resources[] = { { .name = "PEK_DBR", @@ -498,6 +504,11 @@ static struct mfd_cell axp20x_cells[] = { .resources = axp20x_pek_resources, }, { .name = "axp20x-regulator", + }, { + .name = "axp20x-ac-power-supply", + .of_compatible = "x-powers,axp202-ac-power-supply", + .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), + .resources = axp20x_ac_power_supply_resources, }, { .name = "axp20x-usb-power-supply", .of_compatible = "x-powers,axp202-usb-power-supply", From 409b6246cd1c564ea377d5cbe8c6fd184e96119e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 26 Apr 2016 17:06:19 +0100 Subject: [PATCH 66/73] mfd: wm5110: ARIZONA_CLOCK_CONTROL should be volatile Some of the bits in this register can be changed by the codec so we must mark it volatile. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 8e74e71507e7..1ee68bd440fb 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -3066,6 +3066,7 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_AOD_IRQ_RAW_STATUS: case ARIZONA_FX_CTRL2: case ARIZONA_ASRC_STATUS: + case ARIZONA_CLOCK_CONTROL: case ARIZONA_DSP_STATUS: case ARIZONA_DSP1_STATUS_1: case ARIZONA_DSP1_STATUS_2: From b49b927f16acee626c56a1af4ab4cb062f75b5df Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 9 May 2016 11:28:37 +0300 Subject: [PATCH 67/73] mfd: omap-usb-tll: Fix scheduling while atomic BUG We shouldn't be calling clk_prepare_enable()/clk_prepare_disable() in an atomic context. Fixes the following issue: [ 5.830970] ehci-omap: OMAP-EHCI Host Controller driver [ 5.830974] driver_register 'ehci-omap' [ 5.895849] driver_register 'wl1271_sdio' [ 5.896870] BUG: scheduling while atomic: udevd/994/0x00000002 [ 5.896876] 4 locks held by udevd/994: [ 5.896904] #0: (&dev->mutex){......}, at: [] __driver_attach+0x60/0xac [ 5.896923] #1: (&dev->mutex){......}, at: [] __driver_attach+0x70/0xac [ 5.896946] #2: (tll_lock){+.+...}, at: [] omap_tll_enable+0x2c/0xd0 [ 5.896966] #3: (prepare_lock){+.+...}, at: [] clk_prepare_lock+0x48/0xe0 [ 5.897042] Modules linked in: wlcore_sdio(+) ehci_omap(+) dwc3_omap snd_soc_ts3a225e leds_is31fl319x bq27xxx_battery_i2c tsc2007 bq27xxx_battery bq2429x_charger ina2xx tca8418_keypad as5013 leds_tca6507 twl6040_vibra gpio_twl6040 bmp085_i2c(+) palmas_gpadc usb3503 palmas_pwrbutton bmg160_i2c(+) bmp085 bma150(+) bmg160_core bmp280 input_polldev snd_soc_omap_mcbsp snd_soc_omap_mcpdm snd_soc_omap snd_pcm_dmaengine [ 5.897048] Preemption disabled at:[< (null)>] (null) [ 5.897051] [ 5.897059] CPU: 0 PID: 994 Comm: udevd Not tainted 4.6.0-rc5-letux+ #233 [ 5.897062] Hardware name: Generic OMAP5 (Flattened Device Tree) [ 5.897076] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 5.897087] [] (show_stack) from [] (dump_stack+0x88/0xc0) [ 5.897099] [] (dump_stack) from [] (__schedule_bug+0xac/0xd0) [ 5.897111] [] (__schedule_bug) from [] (__schedule+0x88/0x7e4) [ 5.897120] [] (__schedule) from [] (schedule+0x9c/0xc0) [ 5.897129] [] (schedule) from [] (schedule_preempt_disabled+0x14/0x20) [ 5.897140] [] (schedule_preempt_disabled) from [] (mutex_lock_nested+0x258/0x43c) [ 5.897150] [] (mutex_lock_nested) from [] (clk_prepare_lock+0x48/0xe0) [ 5.897160] [] (clk_prepare_lock) from [] (clk_prepare+0x10/0x28) [ 5.897169] [] (clk_prepare) from [] (omap_tll_enable+0x64/0xd0) [ 5.897180] [] (omap_tll_enable) from [] (usbhs_runtime_resume+0x18/0x17c) [ 5.897192] [] (usbhs_runtime_resume) from [] (pm_generic_runtime_resume+0x2c/0x40) [ 5.897202] [] (pm_generic_runtime_resume) from [] (__rpm_callback+0x38/0x68) [ 5.897210] [] (__rpm_callback) from [] (rpm_callback+0x70/0x88) [ 5.897218] [] (rpm_callback) from [] (rpm_resume+0x4ec/0x7ec) [ 5.897227] [] (rpm_resume) from [] (__pm_runtime_resume+0x4c/0x64) [ 5.897236] [] (__pm_runtime_resume) from [] (driver_probe_device+0x30/0x70) [ 5.897246] [] (driver_probe_device) from [] (__driver_attach+0x88/0xac) [ 5.897256] [] (__driver_attach) from [] (bus_for_each_dev+0x50/0x84) [ 5.897267] [] (bus_for_each_dev) from [] (bus_add_driver+0xcc/0x1e4) [ 5.897276] [] (bus_add_driver) from [] (driver_register+0xac/0xf4) [ 5.897286] [] (driver_register) from [] (do_one_initcall+0x100/0x1b8) [ 5.897296] [] (do_one_initcall) from [] (do_init_module+0x58/0x1c0) [ 5.897304] [] (do_init_module) from [] (SyS_finit_module+0x88/0x90) [ 5.897313] [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x1c) [ 5.912697] ------------[ cut here ]------------ [ 5.912711] WARNING: CPU: 0 PID: 994 at kernel/sched/core.c:2996 _raw_spin_unlock+0x28/0x58 [ 5.912717] DEBUG_LOCKS_WARN_ON(val > preempt_count()) Cc: Reported-by: H. Nikolaus Schaller Tested-by: H. Nikolaus Schaller Signed-off-by: Roger Quadros Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-tll.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index b7b3e8ee64f2..c30290f33430 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -269,6 +269,8 @@ static int usbtll_omap_probe(struct platform_device *pdev) if (IS_ERR(tll->ch_clk[i])) dev_dbg(dev, "can't get clock : %s\n", clkname); + else + clk_prepare(tll->ch_clk[i]); } pm_runtime_put_sync(dev); @@ -301,9 +303,12 @@ static int usbtll_omap_remove(struct platform_device *pdev) tll_dev = NULL; spin_unlock(&tll_lock); - for (i = 0; i < tll->nch; i++) - if (!IS_ERR(tll->ch_clk[i])) + for (i = 0; i < tll->nch; i++) { + if (!IS_ERR(tll->ch_clk[i])) { + clk_unprepare(tll->ch_clk[i]); clk_put(tll->ch_clk[i]); + } + } pm_runtime_disable(&pdev->dev); return 0; @@ -420,7 +425,7 @@ int omap_tll_enable(struct usbhs_omap_platform_data *pdata) if (IS_ERR(tll->ch_clk[i])) continue; - r = clk_prepare_enable(tll->ch_clk[i]); + r = clk_enable(tll->ch_clk[i]); if (r) { dev_err(tll_dev, "Error enabling ch %d clock: %d\n", i, r); @@ -448,7 +453,7 @@ int omap_tll_disable(struct usbhs_omap_platform_data *pdata) for (i = 0; i < tll->nch; i++) { if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { if (!IS_ERR(tll->ch_clk[i])) - clk_disable_unprepare(tll->ch_clk[i]); + clk_disable(tll->ch_clk[i]); } } From 37ac9c9029905b5b3a3e4526fdcde1892d8f5501 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 2 May 2016 10:27:37 +0100 Subject: [PATCH 68/73] mfd: arizona: Add defines for GPSW values that can be used from DT Add defines for the possible values the GPSW can be set to using the wlf,gpsw device tree binding. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- include/dt-bindings/mfd/arizona.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/dt-bindings/mfd/arizona.h b/include/dt-bindings/mfd/arizona.h index c40f665e2712..dedf46ffdb53 100644 --- a/include/dt-bindings/mfd/arizona.h +++ b/include/dt-bindings/mfd/arizona.h @@ -110,4 +110,9 @@ #define ARIZONA_ACCDET_MODE_HPM 4 #define ARIZONA_ACCDET_MODE_ADC 7 +#define ARIZONA_GPSW_OPEN 0 +#define ARIZONA_GPSW_CLOSED 1 +#define ARIZONA_GPSW_CLAMP_ENABLED 2 +#define ARIZONA_GPSW_CLAMP_DISABLED 3 + #endif From 327156c593600e0f08575621c2a56f311d482e7a Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 28 Apr 2016 15:28:56 +0530 Subject: [PATCH 69/73] mfd: max77620: Add core driver for MAX77620/MAX20024 MAX77620/MAX20024 are Power Management IC from the MAXIM. It supports RTC, multiple GPIOs, multiple DCDC and LDOs, watchdog, clock etc. Add MFD drier to provides common support for accessing the device; additional drivers is developed on respected subsystem in order to use the functionality of the device. Signed-off-by: Laxman Dewangan Signed-off-by: Mallikarjun Kasoju Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 15 + drivers/mfd/Makefile | 1 + drivers/mfd/max77620.c | 590 +++++++++++++++++++++++++++++++++++ include/linux/mfd/max77620.h | 346 ++++++++++++++++++++ 4 files changed, 952 insertions(+) create mode 100644 drivers/mfd/max77620.c create mode 100644 include/linux/mfd/max77620.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index cf7cbba61971..16d0beffc1cd 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -527,6 +527,21 @@ config MFD_MAX14577 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX77620 + bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" + depends on I2C=y + depends on OF + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + select IRQ_DOMAIN + help + Say yes here to add support for Maxim Semiconductor MAX77620 and + MAX20024 which are Power Management IC with General purpose pins, + RTC, regulators, clock generator, watchdog etc. This driver + provides common support for accessing the device; additional drivers + must be enabled in order to use the functionality of the device. + config MFD_MAX77686 tristate "Maxim Semiconductor MAX77686/802 PMIC Support" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5eaa6465d0a6..921a08dad9b3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -128,6 +128,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o obj-$(CONFIG_MFD_DA9150) += da9150-core.o obj-$(CONFIG_MFD_MAX14577) += max14577.o +obj-$(CONFIG_MFD_MAX77620) += max77620.o obj-$(CONFIG_MFD_MAX77686) += max77686.o obj-$(CONFIG_MFD_MAX77693) += max77693.o obj-$(CONFIG_MFD_MAX77843) += max77843.o diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c new file mode 100644 index 000000000000..199d261990be --- /dev/null +++ b/drivers/mfd/max77620.c @@ -0,0 +1,590 @@ +/* + * Maxim MAX77620 MFD Driver + * + * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. + * + * Author: + * Laxman Dewangan + * Chaitanya Bandi + * Mallikarjun Kasoju + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/****************** Teminology used in driver ******************** + * Here are some terminology used from datasheet for quick reference: + * Flexible Power Sequence (FPS): + * The Flexible Power Sequencer (FPS) allows each regulator to power up under + * hardware or software control. Additionally, each regulator can power on + * independently or among a group of other regulators with an adjustable + * power-up and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can + * be programmed to be part of a sequence allowing external regulators to be + * sequenced along with internal regulators. 32KHz clock can be programmed to + * be part of a sequence. + * There is 3 FPS confguration registers and all resources are configured to + * any of these FPS or no FPS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct resource gpio_resources[] = { + DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), +}; + +static struct resource power_resources[] = { + DEFINE_RES_IRQ(MAX77620_IRQ_LBT_MBATLOW), +}; + +static struct resource rtc_resources[] = { + DEFINE_RES_IRQ(MAX77620_IRQ_TOP_RTC), +}; + +static struct resource thermal_resources[] = { + DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM1), + DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM2), +}; + +static const struct regmap_irq max77620_top_irqs[] = { + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GLBL, 0, MAX77620_IRQ_TOP_GLBL_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_SD, 0, MAX77620_IRQ_TOP_SD_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_LDO, 0, MAX77620_IRQ_TOP_LDO_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GPIO, 0, MAX77620_IRQ_TOP_GPIO_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_RTC, 0, MAX77620_IRQ_TOP_RTC_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_32K, 0, MAX77620_IRQ_TOP_32K_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_TOP_ONOFF, 0, MAX77620_IRQ_TOP_ONOFF_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_LBT_MBATLOW, 1, MAX77620_IRQ_LBM_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM1, 1, MAX77620_IRQ_TJALRM1_MASK), + REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM2, 1, MAX77620_IRQ_TJALRM2_MASK), +}; + +static const struct mfd_cell max77620_children[] = { + { .name = "max77620-pinctrl", }, + { .name = "max77620-clock", }, + { .name = "max77620-pmic", }, + { .name = "max77620-watchdog", }, + { + .name = "max77620-gpio", + .resources = gpio_resources, + .num_resources = ARRAY_SIZE(gpio_resources), + }, { + .name = "max77620-rtc", + .resources = rtc_resources, + .num_resources = ARRAY_SIZE(rtc_resources), + }, { + .name = "max77620-power", + .resources = power_resources, + .num_resources = ARRAY_SIZE(power_resources), + }, { + .name = "max77620-thermal", + .resources = thermal_resources, + .num_resources = ARRAY_SIZE(thermal_resources), + }, +}; + +static const struct mfd_cell max20024_children[] = { + { .name = "max20024-pinctrl", }, + { .name = "max77620-clock", }, + { .name = "max20024-pmic", }, + { .name = "max77620-watchdog", }, + { + .name = "max77620-gpio", + .resources = gpio_resources, + .num_resources = ARRAY_SIZE(gpio_resources), + }, { + .name = "max77620-rtc", + .resources = rtc_resources, + .num_resources = ARRAY_SIZE(rtc_resources), + }, { + .name = "max20024-power", + .resources = power_resources, + .num_resources = ARRAY_SIZE(power_resources), + }, +}; + +static struct regmap_irq_chip max77620_top_irq_chip = { + .name = "max77620-top", + .irqs = max77620_top_irqs, + .num_irqs = ARRAY_SIZE(max77620_top_irqs), + .num_regs = 2, + .status_base = MAX77620_REG_IRQTOP, + .mask_base = MAX77620_REG_IRQTOPM, +}; + +static const struct regmap_range max77620_readable_ranges[] = { + regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), +}; + +static const struct regmap_access_table max77620_readable_table = { + .yes_ranges = max77620_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(max77620_readable_ranges), +}; + +static const struct regmap_range max20024_readable_ranges[] = { + regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), + regmap_reg_range(MAX20024_REG_MAX_ADD, MAX20024_REG_MAX_ADD), +}; + +static const struct regmap_access_table max20024_readable_table = { + .yes_ranges = max20024_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(max20024_readable_ranges), +}; + +static const struct regmap_range max77620_writable_ranges[] = { + regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), +}; + +static const struct regmap_access_table max77620_writable_table = { + .yes_ranges = max77620_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(max77620_writable_ranges), +}; + +static const struct regmap_range max77620_cacheable_ranges[] = { + regmap_reg_range(MAX77620_REG_SD0_CFG, MAX77620_REG_LDO_CFG3), + regmap_reg_range(MAX77620_REG_FPS_CFG0, MAX77620_REG_FPS_SD3), +}; + +static const struct regmap_access_table max77620_volatile_table = { + .no_ranges = max77620_cacheable_ranges, + .n_no_ranges = ARRAY_SIZE(max77620_cacheable_ranges), +}; + +static const struct regmap_config max77620_regmap_config = { + .name = "power-slave", + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX77620_REG_DVSSD4 + 1, + .cache_type = REGCACHE_RBTREE, + .rd_table = &max77620_readable_table, + .wr_table = &max77620_writable_table, + .volatile_table = &max77620_volatile_table, +}; + +static const struct regmap_config max20024_regmap_config = { + .name = "power-slave", + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX20024_REG_MAX_ADD + 1, + .cache_type = REGCACHE_RBTREE, + .rd_table = &max20024_readable_table, + .wr_table = &max77620_writable_table, + .volatile_table = &max77620_volatile_table, +}; + +/* max77620_get_fps_period_reg_value: Get FPS bit field value from + * requested periods. + * MAX77620 supports the FPS period of 40, 80, 160, 320, 540, 1280, 2560 + * and 5120 microseconds. MAX20024 supports the FPS period of 20, 40, 80, + * 160, 320, 540, 1280 and 2560 microseconds. + * The FPS register has 3 bits field to set the FPS period as + * bits max77620 max20024 + * 000 40 20 + * 001 80 40 + * ::: +*/ +static int max77620_get_fps_period_reg_value(struct max77620_chip *chip, + int tperiod) +{ + int fps_min_period; + int i; + + switch (chip->chip_id) { + case MAX20024: + fps_min_period = MAX20024_FPS_PERIOD_MIN_US; + break; + case MAX77620: + fps_min_period = MAX77620_FPS_PERIOD_MIN_US; + default: + return -EINVAL; + } + + for (i = 0; i < 7; i++) { + if (fps_min_period >= tperiod) + return i; + fps_min_period *= 2; + } + + return i; +} + +/* max77620_config_fps: Configure FPS configuration registers + * based on platform specific information. + */ +static int max77620_config_fps(struct max77620_chip *chip, + struct device_node *fps_np) +{ + struct device *dev = chip->dev; + unsigned int mask = 0, config = 0; + u32 fps_max_period; + u32 param_val; + int tperiod, fps_id; + int ret; + char fps_name[10]; + + switch (chip->chip_id) { + case MAX20024: + fps_max_period = MAX20024_FPS_PERIOD_MAX_US; + break; + case MAX77620: + fps_max_period = MAX77620_FPS_PERIOD_MAX_US; + default: + return -EINVAL; + } + + for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { + sprintf(fps_name, "fps%d", fps_id); + if (!strcmp(fps_np->name, fps_name)) + break; + } + + if (fps_id == MAX77620_FPS_COUNT) { + dev_err(dev, "FPS node name %s is not valid\n", fps_np->name); + return -EINVAL; + } + + ret = of_property_read_u32(fps_np, "maxim,shutdown-fps-time-period-us", + ¶m_val); + if (!ret) { + mask |= MAX77620_FPS_TIME_PERIOD_MASK; + chip->shutdown_fps_period[fps_id] = min(param_val, + fps_max_period); + tperiod = max77620_get_fps_period_reg_value(chip, + chip->shutdown_fps_period[fps_id]); + config |= tperiod << MAX77620_FPS_TIME_PERIOD_SHIFT; + } + + ret = of_property_read_u32(fps_np, "maxim,suspend-fps-time-period-us", + ¶m_val); + if (!ret) + chip->suspend_fps_period[fps_id] = min(param_val, + fps_max_period); + + ret = of_property_read_u32(fps_np, "maxim,fps-event-source", + ¶m_val); + if (!ret) { + if (param_val > 2) { + dev_err(dev, "FPS%d event-source invalid\n", fps_id); + return -EINVAL; + } + mask |= MAX77620_FPS_EN_SRC_MASK; + config |= param_val << MAX77620_FPS_EN_SRC_SHIFT; + if (param_val == 2) { + mask |= MAX77620_FPS_ENFPS_SW_MASK; + config |= MAX77620_FPS_ENFPS_SW; + } + } + + if (!chip->sleep_enable && !chip->enable_global_lpm) { + ret = of_property_read_u32(fps_np, + "maxim,device-state-on-disabled-event", + ¶m_val); + if (!ret) { + if (param_val == 0) + chip->sleep_enable = true; + else if (param_val == 1) + chip->enable_global_lpm = true; + } + } + + ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, + mask, config); + if (ret < 0) { + dev_err(dev, "Failed to update FPS CFG: %d\n", ret); + return ret; + } + + return 0; +} + +static int max77620_initialise_fps(struct max77620_chip *chip) +{ + struct device *dev = chip->dev; + struct device_node *fps_np, *fps_child; + u8 config; + int fps_id; + int ret; + + for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { + chip->shutdown_fps_period[fps_id] = -1; + chip->suspend_fps_period[fps_id] = -1; + } + + fps_np = of_get_child_by_name(dev->of_node, "fps"); + if (!fps_np) + goto skip_fps; + + for_each_child_of_node(fps_np, fps_child) { + ret = max77620_config_fps(chip, fps_child); + if (ret < 0) + return ret; + } + + config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0; + ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, + MAX77620_ONOFFCNFG2_SLP_LPM_MSK, config); + if (ret < 0) { + dev_err(dev, "Failed to update SLP_LPM: %d\n", ret); + return ret; + } + +skip_fps: + /* Enable wake on EN0 pin */ + ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, + MAX77620_ONOFFCNFG2_WK_EN0, + MAX77620_ONOFFCNFG2_WK_EN0); + if (ret < 0) { + dev_err(dev, "Failed to update WK_EN0: %d\n", ret); + return ret; + } + + /* For MAX20024, SLPEN will be POR reset if CLRSE is b11 */ + if ((chip->chip_id == MAX20024) && chip->sleep_enable) { + config = MAX77620_ONOFFCNFG1_SLPEN | MAX20024_ONOFFCNFG1_CLRSE; + ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, + config, config); + if (ret < 0) { + dev_err(dev, "Failed to update SLPEN: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int max77620_read_es_version(struct max77620_chip *chip) +{ + unsigned int val; + u8 cid_val[6]; + int i; + int ret; + + for (i = MAX77620_REG_CID0; i <= MAX77620_REG_CID5; i++) { + ret = regmap_read(chip->rmap, i, &val); + if (ret < 0) { + dev_err(chip->dev, "Failed to read CID: %d\n", ret); + return ret; + } + dev_dbg(chip->dev, "CID%d: 0x%02x\n", + i - MAX77620_REG_CID0, val); + cid_val[i - MAX77620_REG_CID0] = val; + } + + /* CID4 is OTP Version and CID5 is ES version */ + dev_info(chip->dev, "PMIC Version OTP:0x%02X and ES:0x%X\n", + cid_val[4], MAX77620_CID5_DIDM(cid_val[5])); + + return ret; +} + +static int max77620_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct regmap_config *rmap_config; + struct max77620_chip *chip; + const struct mfd_cell *mfd_cells; + int n_mfd_cells; + int ret; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + i2c_set_clientdata(client, chip); + chip->dev = &client->dev; + chip->irq_base = -1; + chip->chip_irq = client->irq; + chip->chip_id = (enum max77620_chip_id)id->driver_data; + + switch (chip->chip_id) { + case MAX77620: + mfd_cells = max77620_children; + n_mfd_cells = ARRAY_SIZE(max77620_children); + rmap_config = &max77620_regmap_config; + break; + case MAX20024: + mfd_cells = max20024_children; + n_mfd_cells = ARRAY_SIZE(max20024_children); + rmap_config = &max20024_regmap_config; + break; + default: + dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id); + return -EINVAL; + } + + chip->rmap = devm_regmap_init_i2c(client, rmap_config); + if (IS_ERR(chip->rmap)) { + ret = PTR_ERR(chip->rmap); + dev_err(chip->dev, "Failed to intialise regmap: %d\n", ret); + return ret; + } + + ret = max77620_read_es_version(chip); + if (ret < 0) + return ret; + + ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq, + IRQF_ONESHOT | IRQF_SHARED, + chip->irq_base, &max77620_top_irq_chip, + &chip->top_irq_data); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); + return ret; + } + + ret = max77620_initialise_fps(chip); + if (ret < 0) + return ret; + + ret = devm_mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, + mfd_cells, n_mfd_cells, NULL, 0, + regmap_irq_get_domain(chip->top_irq_data)); + if (ret < 0) { + dev_err(chip->dev, "Failed to add MFD children: %d\n", ret); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int max77620_set_fps_period(struct max77620_chip *chip, + int fps_id, int time_period) +{ + int period = max77620_get_fps_period_reg_value(chip, time_period); + int ret; + + ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, + MAX77620_FPS_TIME_PERIOD_MASK, + period << MAX77620_FPS_TIME_PERIOD_SHIFT); + if (ret < 0) { + dev_err(chip->dev, "Failed to update FPS period: %d\n", ret); + return ret; + } + + return 0; +} + +static int max77620_i2c_suspend(struct device *dev) +{ + struct max77620_chip *chip = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + unsigned int config; + int fps; + int ret; + + for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { + if (chip->suspend_fps_period[fps] < 0) + continue; + + ret = max77620_set_fps_period(chip, fps, + chip->suspend_fps_period[fps]); + if (ret < 0) + return ret; + } + + /* + * For MAX20024: No need to configure SLPEN on suspend as + * it will be configured on Init. + */ + if (chip->chip_id == MAX20024) + goto out; + + config = (chip->sleep_enable) ? MAX77620_ONOFFCNFG1_SLPEN : 0; + ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, + MAX77620_ONOFFCNFG1_SLPEN, + config); + if (ret < 0) { + dev_err(dev, "Failed to configure sleep in suspend: %d\n", ret); + return ret; + } + + /* Disable WK_EN0 */ + ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, + MAX77620_ONOFFCNFG2_WK_EN0, 0); + if (ret < 0) { + dev_err(dev, "Failed to configure WK_EN in suspend: %d\n", ret); + return ret; + } + +out: + disable_irq(client->irq); + + return 0; +} + +static int max77620_i2c_resume(struct device *dev) +{ + struct max77620_chip *chip = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + int ret; + int fps; + + for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { + if (chip->shutdown_fps_period[fps] < 0) + continue; + + ret = max77620_set_fps_period(chip, fps, + chip->shutdown_fps_period[fps]); + if (ret < 0) + return ret; + } + + /* + * For MAX20024: No need to configure WKEN0 on resume as + * it is configured on Init. + */ + if (chip->chip_id == MAX20024) + goto out; + + /* Enable WK_EN0 */ + ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, + MAX77620_ONOFFCNFG2_WK_EN0, + MAX77620_ONOFFCNFG2_WK_EN0); + if (ret < 0) { + dev_err(dev, "Failed to configure WK_EN0 n resume: %d\n", ret); + return ret; + } + +out: + enable_irq(client->irq); + + return 0; +} +#endif + +static const struct i2c_device_id max77620_id[] = { + {"max77620", MAX77620}, + {"max20024", MAX20024}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, max77620_id); + +static const struct dev_pm_ops max77620_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max77620_i2c_suspend, max77620_i2c_resume) +}; + +static struct i2c_driver max77620_driver = { + .driver = { + .name = "max77620", + .pm = &max77620_pm_ops, + }, + .probe = max77620_probe, + .id_table = max77620_id, +}; + +module_i2c_driver(max77620_driver); + +MODULE_DESCRIPTION("MAX77620/MAX20024 Multi Function Device Core Driver"); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_AUTHOR("Chaitanya Bandi "); +MODULE_AUTHOR("Mallikarjun Kasoju "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/max77620.h b/include/linux/mfd/max77620.h new file mode 100644 index 000000000000..3ca0af07fc78 --- /dev/null +++ b/include/linux/mfd/max77620.h @@ -0,0 +1,346 @@ +/* + * Defining registers address and its bit definitions of MAX77620 and MAX20024 + * + * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef _MFD_MAX77620_H_ +#define _MFD_MAX77620_H_ + +#include + +/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ +#define MAX77620_REG_CNFGGLBL1 0x00 +#define MAX77620_REG_CNFGGLBL2 0x01 +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_REG_CNFG1_32K 0x03 +#define MAX77620_REG_CNFGBBC 0x04 +#define MAX77620_REG_IRQTOP 0x05 +#define MAX77620_REG_INTLBT 0x06 +#define MAX77620_REG_IRQSD 0x07 +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 +#define MAX77620_REG_IRQ_LVL2_L8 0x09 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A +#define MAX77620_REG_ONOFFIRQ 0x0B +#define MAX77620_REG_NVERC 0x0C +#define MAX77620_REG_IRQTOPM 0x0D +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_REG_STATLBT 0x13 +#define MAX77620_REG_STATSD 0x14 +#define MAX77620_REG_ONOFFSTAT 0x15 + +/* SD and LDO Registers */ +#define MAX77620_REG_SD0 0x16 +#define MAX77620_REG_SD1 0x17 +#define MAX77620_REG_SD2 0x18 +#define MAX77620_REG_SD3 0x19 +#define MAX77620_REG_SD4 0x1A +#define MAX77620_REG_DVSSD0 0x1B +#define MAX77620_REG_DVSSD1 0x1C +#define MAX77620_REG_SD0_CFG 0x1D +#define MAX77620_REG_SD1_CFG 0x1E +#define MAX77620_REG_SD2_CFG 0x1F +#define MAX77620_REG_SD3_CFG 0x20 +#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_REG_LDO0_CFG 0x23 +#define MAX77620_REG_LDO0_CFG2 0x24 +#define MAX77620_REG_LDO1_CFG 0x25 +#define MAX77620_REG_LDO1_CFG2 0x26 +#define MAX77620_REG_LDO2_CFG 0x27 +#define MAX77620_REG_LDO2_CFG2 0x28 +#define MAX77620_REG_LDO3_CFG 0x29 +#define MAX77620_REG_LDO3_CFG2 0x2A +#define MAX77620_REG_LDO4_CFG 0x2B +#define MAX77620_REG_LDO4_CFG2 0x2C +#define MAX77620_REG_LDO5_CFG 0x2D +#define MAX77620_REG_LDO5_CFG2 0x2E +#define MAX77620_REG_LDO6_CFG 0x2F +#define MAX77620_REG_LDO6_CFG2 0x30 +#define MAX77620_REG_LDO7_CFG 0x31 +#define MAX77620_REG_LDO7_CFG2 0x32 +#define MAX77620_REG_LDO8_CFG 0x33 +#define MAX77620_REG_LDO8_CFG2 0x34 +#define MAX77620_REG_LDO_CFG3 0x35 + +#define MAX77620_LDO_SLEW_RATE_MASK 0x1 + +/* LDO Configuration 3 */ +#define MAX77620_TRACK4_MASK BIT(5) +#define MAX77620_TRACK4_SHIFT 5 + +/* Voltage */ +#define MAX77620_SDX_VOLT_MASK 0xFF +#define MAX77620_SD0_VOLT_MASK 0x3F +#define MAX77620_SD1_VOLT_MASK 0x7F +#define MAX77620_LDO_VOLT_MASK 0x3F + +#define MAX77620_REG_GPIO0 0x36 +#define MAX77620_REG_GPIO1 0x37 +#define MAX77620_REG_GPIO2 0x38 +#define MAX77620_REG_GPIO3 0x39 +#define MAX77620_REG_GPIO4 0x3A +#define MAX77620_REG_GPIO5 0x3B +#define MAX77620_REG_GPIO6 0x3C +#define MAX77620_REG_GPIO7 0x3D +#define MAX77620_REG_PUE_GPIO 0x3E +#define MAX77620_REG_PDE_GPIO 0x3F +#define MAX77620_REG_AME_GPIO 0x40 +#define MAX77620_REG_ONOFFCNFG1 0x41 +#define MAX77620_REG_ONOFFCNFG2 0x42 + +/* FPS Registers */ +#define MAX77620_REG_FPS_CFG0 0x43 +#define MAX77620_REG_FPS_CFG1 0x44 +#define MAX77620_REG_FPS_CFG2 0x45 +#define MAX77620_REG_FPS_LDO0 0x46 +#define MAX77620_REG_FPS_LDO1 0x47 +#define MAX77620_REG_FPS_LDO2 0x48 +#define MAX77620_REG_FPS_LDO3 0x49 +#define MAX77620_REG_FPS_LDO4 0x4A +#define MAX77620_REG_FPS_LDO5 0x4B +#define MAX77620_REG_FPS_LDO6 0x4C +#define MAX77620_REG_FPS_LDO7 0x4D +#define MAX77620_REG_FPS_LDO8 0x4E +#define MAX77620_REG_FPS_SD0 0x4F +#define MAX77620_REG_FPS_SD1 0x50 +#define MAX77620_REG_FPS_SD2 0x51 +#define MAX77620_REG_FPS_SD3 0x52 +#define MAX77620_REG_FPS_SD4 0x53 +#define MAX77620_REG_FPS_NONE 0 + +#define MAX77620_FPS_SRC_MASK 0xC0 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 + +/* Minimum and maximum FPS period time (in microseconds) are + * different for MAX77620 and Max20024. + */ +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX20024_FPS_PERIOD_MIN_US 20 + +#define MAX77620_FPS_PERIOD_MAX_US 2560 +#define MAX20024_FPS_PERIOD_MAX_US 5120 + +#define MAX77620_REG_FPS_GPIO1 0x54 +#define MAX77620_REG_FPS_GPIO2 0x55 +#define MAX77620_REG_FPS_GPIO3 0x56 +#define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_REG_CID0 0x58 +#define MAX77620_REG_CID1 0x59 +#define MAX77620_REG_CID2 0x5A +#define MAX77620_REG_CID3 0x5B +#define MAX77620_REG_CID4 0x5C +#define MAX77620_REG_CID5 0x5D + +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 + +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 + +/* CNCG2SD */ +#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2) + +/* Device Identification Metal */ +#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) +/* Device Indentification OTP */ +#define MAX77620_CID5_DIDO(n) ((n) & 0xF) + +/* SD CNFG1 */ +#define MAX77620_SD_SR_MASK 0xC0 +#define MAX77620_SD_SR_SHIFT 6 +#define MAX77620_SD_POWER_MODE_MASK 0x30 +#define MAX77620_SD_POWER_MODE_SHIFT 4 +#define MAX77620_SD_CFG1_ADE_MASK BIT(3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE BIT(3) +#define MAX77620_SD_FPWM_MASK 0x04 +#define MAX77620_SD_FPWM_SHIFT 2 +#define MAX77620_SD_FSRADE_MASK 0x01 +#define MAX77620_SD_FSRADE_SHIFT 0 +#define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0) + +/* LDO_CNFG2 */ +#define MAX77620_LDO_POWER_MODE_MASK 0xC0 +#define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX77620_LDO_CFG2_ADE_MASK BIT(1) +#define MAX77620_LDO_CFG2_ADE_DISABLE 0 +#define MAX77620_LDO_CFG2_ADE_ENABLE BIT(1) +#define MAX77620_LDO_CFG2_SS_MASK BIT(0) +#define MAX77620_LDO_CFG2_SS_FAST BIT(0) +#define MAX77620_LDO_CFG2_SS_SLOW 0 + +#define MAX77620_IRQ_TOP_GLBL_MASK BIT(7) +#define MAX77620_IRQ_TOP_SD_MASK BIT(6) +#define MAX77620_IRQ_TOP_LDO_MASK BIT(5) +#define MAX77620_IRQ_TOP_GPIO_MASK BIT(4) +#define MAX77620_IRQ_TOP_RTC_MASK BIT(3) +#define MAX77620_IRQ_TOP_32K_MASK BIT(2) +#define MAX77620_IRQ_TOP_ONOFF_MASK BIT(1) + +#define MAX77620_IRQ_LBM_MASK BIT(3) +#define MAX77620_IRQ_TJALRM1_MASK BIT(2) +#define MAX77620_IRQ_TJALRM2_MASK BIT(1) + +#define MAX77620_PWR_I2C_ADDR 0x3c +#define MAX77620_RTC_I2C_ADDR 0x68 + +#define MAX77620_CNFG_GPIO_DRV_MASK BIT(0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL BIT(0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0 +#define MAX77620_CNFG_GPIO_DIR_MASK BIT(1) +#define MAX77620_CNFG_GPIO_DIR_INPUT BIT(1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0 +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK BIT(2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK BIT(3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH BIT(3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0 +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING BIT(4) +#define MAX77620_CNFG_GPIO_INT_RISING BIT(5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) + +#define MAX77620_IRQ_LVL2_GPIO_EDGE0 BIT(0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 BIT(1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 BIT(2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 BIT(3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 BIT(4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 BIT(5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 BIT(6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 BIT(7) + +#define MAX77620_CNFG1_32K_OUT0_EN BIT(2) + +#define MAX77620_ONOFFCNFG1_SFT_RST BIT(7) +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_SLPEN BIT(2) +#define MAX77620_ONOFFCNFG1_PWR_OFF BIT(1) +#define MAX20024_ONOFFCNFG1_CLRSE 0x18 + +#define MAX77620_ONOFFCNFG2_SFT_RST_WK BIT(7) +#define MAX77620_ONOFFCNFG2_WD_RST_WK BIT(6) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK BIT(5) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 BIT(2) +#define MAX77620_ONOFFCNFG2_WK_EN0 BIT(0) + +#define MAX77620_GLBLM_MASK BIT(0) + +#define MAX77620_WDTC_MASK 0x3 +#define MAX77620_WDTOFFC BIT(4) +#define MAX77620_WDTSLPC BIT(3) +#define MAX77620_WDTEN BIT(2) + +#define MAX77620_TWD_MASK 0x3 +#define MAX77620_TWD_2s 0x0 +#define MAX77620_TWD_16s 0x1 +#define MAX77620_TWD_64s 0x2 +#define MAX77620_TWD_128s 0x3 + +#define MAX77620_CNFGGLBL1_LBDAC_EN BIT(7) +#define MAX77620_CNFGGLBL1_MPPLD BIT(6) +#define MAX77620_CNFGGLBL1_LBHYST (BIT(5) | BIT(4)) +#define MAX77620_CNFGGLBL1_LBDAC 0x0E +#define MAX77620_CNFGGLBL1_LBRSTEN BIT(0) + +/* CNFG BBC registers */ +#define MAX77620_CNFGBBC_ENABLE BIT(0) +#define MAX77620_CNFGBBC_CURRENT_MASK 0x06 +#define MAX77620_CNFGBBC_CURRENT_SHIFT 1 +#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 +#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 +#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE BIT(5) +#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 +#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 + +#define MAX77620_FPS_COUNT 3 + +/* Interrupts */ +enum { + MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ + MAX77620_IRQ_TOP_SD, /* SD power fail */ + MAX77620_IRQ_TOP_LDO, /* LDO power fail */ + MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ + MAX77620_IRQ_TOP_RTC, /* RTC */ + MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ + MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ + MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ +}; + +/* GPIOs */ +enum { + MAX77620_GPIO0, + MAX77620_GPIO1, + MAX77620_GPIO2, + MAX77620_GPIO3, + MAX77620_GPIO4, + MAX77620_GPIO5, + MAX77620_GPIO6, + MAX77620_GPIO7, + MAX77620_GPIO_NR, +}; + +/* FPS Source */ +enum max77620_fps_src { + MAX77620_FPS_SRC_0, + MAX77620_FPS_SRC_1, + MAX77620_FPS_SRC_2, + MAX77620_FPS_SRC_NONE, + MAX77620_FPS_SRC_DEF, +}; + +enum max77620_chip_id { + MAX77620, + MAX20024, +}; + +struct max77620_chip { + struct device *dev; + struct regmap *rmap; + + int chip_irq; + int irq_base; + + /* chip id */ + enum max77620_chip_id chip_id; + + bool sleep_enable; + bool enable_global_lpm; + int shutdown_fps_period[MAX77620_FPS_COUNT]; + int suspend_fps_period[MAX77620_FPS_COUNT]; + + struct regmap_irq_chip_data *top_irq_data; + struct regmap_irq_chip_data *gpio_irq_data; +}; + +#endif /* _MFD_MAX77620_H_ */ From e5e3dea890804134f65d51eb42963b8659908d40 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 28 Apr 2016 15:28:55 +0530 Subject: [PATCH 70/73] mfd: Add device-tree binding doc for PMIC MAX77620/MAX20024 The MAXIM PMIC MAX77620 and MAX20024 are power management IC which supports RTC, GPIO, DCDC/LDO regulators, interrupt, watchdog etc. Add DT binding document for the different functionality of this device. Signed-off-by: Laxman Dewangan Acked-by: Rob Herring Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/max77620.txt | 143 ++++++++++++++++++ include/dt-bindings/mfd/max77620.h | 39 +++++ 2 files changed, 182 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/max77620.txt create mode 100644 include/dt-bindings/mfd/max77620.h diff --git a/Documentation/devicetree/bindings/mfd/max77620.txt b/Documentation/devicetree/bindings/mfd/max77620.txt new file mode 100644 index 000000000000..2ad44f7e4880 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/max77620.txt @@ -0,0 +1,143 @@ +MAX77620 Power management IC from Maxim Semiconductor. + +Required properties: +------------------- +- compatible: Must be one of + "maxim,max77620" + "maxim,max20024". +- reg: I2C device address. + +Optional properties: +------------------- +- interrupts: The interrupt on the parent the controller is + connected to. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: is <2> and their usage is compliant to the 2 cells + variant of <../interrupt-controller/interrupts.txt> + IRQ numbers for different interrupt source of MAX77620 + are defined at dt-bindings/mfd/max77620.h. + +Optional subnodes and their properties: +======================================= + +Flexible power sequence configurations: +-------------------------------------- +The Flexible Power Sequencer (FPS) allows each regulator to power up under +hardware or software control. Additionally, each regulator can power on +independently or among a group of other regulators with an adjustable power-up +and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can be programmed +to be part of a sequence allowing external regulators to be sequenced along +with internal regulators. 32KHz clock can be programmed to be part of a +sequence. + +The flexible sequencing structure consists of two hardware enable inputs +(EN0, EN1), and 3 master sequencing timers called FPS0, FPS1 and FPS2. +Each master sequencing timer is programmable through its configuration +register to have a hardware enable source (EN1 or EN2) or a software enable +source (SW). When enabled/disabled, the master sequencing timer generates +eight sequencing events on different time periods called slots. The time +period between each event is programmable within the configuration register. +Each regulator, GPIO1, GPIO2, GPIO3, and 32KHz clock has a flexible power +sequence slave register which allows its enable source to be specified as +a flexible power sequencer timer or a software bit. When a FPS source of +regulators, GPIOs and clocks specifies the enable source to be a flexible +power sequencer, the power up and power down delays can be specified in +the regulators, GPIOs and clocks flexible power sequencer configuration +registers. + +When FPS event cleared (set to LOW), regulators, GPIOs and 32KHz +clock are set into following state at the sequencing event that +corresponds to its flexible sequencer configuration register. + Sleep state: In this state, regulators, GPIOs + and 32KHz clock get disabled at + the sequencing event. + Global Low Power Mode (GLPM): In this state, regulators are set in + low power mode at the sequencing event. + +The configuration parameters of FPS is provided through sub-node "fps" +and their child for FPS specific. The child node name for FPS are "fps0", +"fps1", and "fps2" for FPS0, FPS1 and FPS2 respectively. + +The FPS configurations like FPS source, power up and power down slots for +regulators, GPIOs and 32kHz clocks are provided in their respective +configuration nodes which is explained in respective sub-system DT +binding document. + +There is need for different FPS configuration parameters based on system +state like when system state changed from active to suspend or active to +power off (shutdown). + +Optional properties: +------------------- +-maxim,fps-event-source: u32, FPS event source like external + hardware input to PMIC i.e. EN0, EN1 or + software (SW). + The macros are defined on + dt-bindings/mfd/max77620.h + for different control source. + - MAX77620_FPS_EVENT_SRC_EN0 + for hardware input pin EN0. + - MAX77620_FPS_EVENT_SRC_EN1 + for hardware input pin EN1. + - MAX77620_FPS_EVENT_SRC_SW + for software control. + +-maxim,shutdown-fps-time-period-us: u32, FPS time period in microseconds + when system enters in to shutdown + state. + +-maxim,suspend-fps-time-period-us: u32, FPS time period in microseconds + when system enters in to suspend state. + +-maxim,device-state-on-disabled-event: u32, describe the PMIC state when FPS + event cleared (set to LOW) whether it + should go to sleep state or low-power + state. Following are valid values: + - MAX77620_FPS_INACTIVE_STATE_SLEEP + to set the PMIC state to sleep. + - MAX77620_FPS_INACTIVE_STATE_LOW_POWER + to set the PMIC state to low + power. + Absence of this property or other value + will not change device state when FPS + event get cleared. + +Here supported time periods by device in microseconds are as follows: +MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds. +MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds. + +For DT binding details of different sub modules like GPIO, pincontrol, +regulator, power, please refer respective device-tree binding document +under their respective sub-system directories. + +Example: +-------- +#include + +max77620@3c { + compatible = "maxim,max77620"; + reg = <0x3c>; + + interrupt-parent = <&intc>; + interrupts = <0 86 IRQ_TYPE_NONE>; + + interrupt-controller; + #interrupt-cells = <2>; + + fps { + fps0 { + maxim,shutdown-fps-time-period-us = <1280>; + maxim,fps-event-source = ; + }; + + fps1 { + maxim,shutdown-fps-time-period-us = <1280>; + maxim,fps-event-source = ; + }; + + fps2 { + maxim,shutdown-fps-time-period-us = <1280>; + maxim,fps-event-source = ; + }; + }; +}; diff --git a/include/dt-bindings/mfd/max77620.h b/include/dt-bindings/mfd/max77620.h new file mode 100644 index 000000000000..b911a0720ccd --- /dev/null +++ b/include/dt-bindings/mfd/max77620.h @@ -0,0 +1,39 @@ +/* + * This header provides macros for MAXIM MAX77620 device bindings. + * + * Copyright (c) 2016, NVIDIA Corporation. + * Author: Laxman Dewangan + */ + +#ifndef _DT_BINDINGS_MFD_MAX77620_H +#define _DT_BINDINGS_MFD_MAX77620_H + +/* MAX77620 interrupts */ +#define MAX77620_IRQ_TOP_GLBL 0 /* Low-Battery */ +#define MAX77620_IRQ_TOP_SD 1 /* SD power fail */ +#define MAX77620_IRQ_TOP_LDO 2 /* LDO power fail */ +#define MAX77620_IRQ_TOP_GPIO 3 /* GPIO internal int to MAX77620 */ +#define MAX77620_IRQ_TOP_RTC 4 /* RTC */ +#define MAX77620_IRQ_TOP_32K 5 /* 32kHz oscillator */ +#define MAX77620_IRQ_TOP_ONOFF 6 /* ON/OFF oscillator */ +#define MAX77620_IRQ_LBT_MBATLOW 7 /* Thermal alarm status, > 120C */ +#define MAX77620_IRQ_LBT_TJALRM1 8 /* Thermal alarm status, > 120C */ +#define MAX77620_IRQ_LBT_TJALRM2 9 /* Thermal alarm status, > 140C */ + +/* FPS event source */ +#define MAX77620_FPS_EVENT_SRC_EN0 0 +#define MAX77620_FPS_EVENT_SRC_EN1 1 +#define MAX77620_FPS_EVENT_SRC_SW 2 + +/* Device state when FPS event LOW */ +#define MAX77620_FPS_INACTIVE_STATE_SLEEP 0 +#define MAX77620_FPS_INACTIVE_STATE_LOW_POWER 1 + +/* FPS source */ +#define MAX77620_FPS_SRC_0 0 +#define MAX77620_FPS_SRC_1 1 +#define MAX77620_FPS_SRC_2 2 +#define MAX77620_FPS_SRC_NONE 3 +#define MAX77620_FPS_SRC_DEF 4 + +#endif From fcdad4210fc001b2d46f4bf97a2860792f4265f8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 27 Apr 2016 19:49:22 +0200 Subject: [PATCH 71/73] mfd: vexpress: Add !ARCH_USES_GETTIMEOFFSET dependency The MFD_VEXPRESS_SYSREG driver selects CLKSRC_MMIO, which in turn conflicts with ARCH_USES_GETTIMEOFFSET, causing a harmless Kconfig warning when it is set: warning: (ARCH_MVEBU && ARCH_DIGICOLOR && ARCH_GEMINI && ARCH_KEYSTONE && ARCH_MOXART && ARCH_MXS && PLAT_SPEAR && ARCH_SUNXI && ARCH_TEGRA && ARCH_U300 && PLAT_ORION && ARCH_CLPS711X && ARCH_EP93XX && ARCH_NETX && ARCH_IXP4XX && ARCH_KS8695 && ARCH_W90X900 && ARCH_PXA && ARCH_SA1100 && ARCH_OMAP1 && ARCH_BCM_IPROC && ARCH_INTEGRATOR_AP && ARCH_OMAP2PLUS && MFD_VEXPRESS_SYSREG) selects CLKSRC_MMIO which has unmet direct dependencies (!ARCH_USES_GETTIMEOFFSET) This was apparently hidden by the fact that no ARM platform that still sets ARCH_USES_GETTIMEOFFSET has gpiolib support, and we already have a dependency on GPIOLIB that I added a while ago. However, after 296ad4acb8ef ("gpio: remove deps on ARCH_[WANT_OPTIONAL|REQUIRE]_GPIOLIB"), any platform can enable CONFIG_GPIOLIB, and that lets us enable MFD_VEXPRESS_SYSREG as well. This adds an explicit dependency on !ARCH_USES_GETTIMEOFFSET to guarantee that we can enable the CLKSRC_MMIO driver without getting warnings. Signed-off-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 16d0beffc1cd..a49565cc1a6b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1583,7 +1583,7 @@ endmenu config MFD_VEXPRESS_SYSREG bool "Versatile Express System Registers" - depends on VEXPRESS_CONFIG && GPIOLIB + depends on VEXPRESS_CONFIG && GPIOLIB && !ARCH_USES_GETTIMEOFFSET default y select CLKSRC_MMIO select GPIO_GENERIC_PLATFORM From 68b21094ef9ba3ef0dd8b1e24b03e00cd3b34e26 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 25 Apr 2016 22:42:25 +0100 Subject: [PATCH 72/73] mfd: ab8500-debugfs: Trivial fix of spelling mistake on "between" fix spelling mistake, beetween -> between Signed-off-by: Colin Ian King Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 69d9fffe5b5c..0aecd7bd35f8 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -2563,7 +2563,7 @@ static ssize_t ab8500_gpadc_trig_timer_write(struct file *file, if (user_trig_timer & ~0xFF) { dev_err(dev, - "debugfs error input: should be beetween 0 to 255\n"); + "debugfs error input: should be between 0 to 255\n"); return -EINVAL; } From b52207ef4ea56f8c22288ec3387399aac72c26cf Mon Sep 17 00:00:00 2001 From: Chen Feng Date: Sun, 14 Feb 2016 14:29:21 +0800 Subject: [PATCH 73/73] mfd: hi655x: Add MFD driver for hi655x Add PMIC MFD driver to support hisilicon hi665x. Signed-off-by: Chen Feng Signed-off-by: Fei Wang Signed-off-by: Xinwei Kong Reviewed-by: Haojian Zhuang Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 10 ++ drivers/mfd/Makefile | 1 + drivers/mfd/hi655x-pmic.c | 162 ++++++++++++++++++++++++++++++++ include/linux/mfd/hi655x-pmic.h | 55 +++++++++++ 4 files changed, 228 insertions(+) create mode 100644 drivers/mfd/hi655x-pmic.c create mode 100644 include/linux/mfd/hi655x-pmic.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a49565cc1a6b..1bcf601de5bc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -319,6 +319,16 @@ config MFD_HI6421_PMIC menus in order to enable them. We communicate with the Hi6421 via memory-mapped I/O. +config MFD_HI655X_PMIC + tristate "HiSilicon Hi655X series PMU/Codec IC" + depends on ARCH_HISI || COMPILE_TEST + depends on OF + select MFD_CORE + select REGMAP_MMIO + select REGMAP_IRQ + help + Select this option to enable Hisilicon hi655x series pmic driver. + config HTC_EGPIO bool "HTC EGPIO support" depends on GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 921a08dad9b3..42a66e19e191 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -196,6 +196,7 @@ obj-$(CONFIG_MFD_STW481X) += stw481x.o obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o +obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o obj-$(CONFIG_MFD_DLN2) += dln2.o obj-$(CONFIG_MFD_RT5033) += rt5033.o obj-$(CONFIG_MFD_SKY81452) += sky81452.o diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c new file mode 100644 index 000000000000..05ddc7882362 --- /dev/null +++ b/drivers/mfd/hi655x-pmic.c @@ -0,0 +1,162 @@ +/* + * Device driver for MFD hi655x PMIC + * + * Copyright (c) 2016 Hisilicon. + * + * Authors: + * Chen Feng + * Fei Wang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell hi655x_pmic_devs[] = { + { .name = "hi655x-regulator", }, +}; + +static const struct regmap_irq hi655x_irqs[] = { + { .reg_offset = 0, .mask = OTMP_D1R_INT }, + { .reg_offset = 0, .mask = VSYS_2P5_R_INT }, + { .reg_offset = 0, .mask = VSYS_UV_D3R_INT }, + { .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT }, + { .reg_offset = 0, .mask = PWRON_D4SR_INT }, + { .reg_offset = 0, .mask = PWRON_D20F_INT }, + { .reg_offset = 0, .mask = PWRON_D20R_INT }, + { .reg_offset = 0, .mask = RESERVE_INT }, +}; + +static const struct regmap_irq_chip hi655x_irq_chip = { + .name = "hi655x-pmic", + .irqs = hi655x_irqs, + .num_regs = 1, + .num_irqs = ARRAY_SIZE(hi655x_irqs), + .status_base = HI655X_IRQ_STAT_BASE, + .mask_base = HI655X_IRQ_MASK_BASE, +}; + +static struct regmap_config hi655x_regmap_config = { + .reg_bits = 32, + .reg_stride = HI655X_STRIDE, + .val_bits = 8, + .max_register = HI655X_BUS_ADDR(0xFFF), +}; + +static void hi655x_local_irq_clear(struct regmap *map) +{ + int i; + + regmap_write(map, HI655X_ANA_IRQM_BASE, HI655X_IRQ_CLR); + for (i = 0; i < HI655X_IRQ_ARRAY; i++) { + regmap_write(map, HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE, + HI655X_IRQ_CLR); + } +} + +static int hi655x_pmic_probe(struct platform_device *pdev) +{ + int ret; + struct hi655x_pmic *pmic; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *base; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + pmic->dev = dev; + + pmic->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!pmic->res) + return -ENOENT; + + base = devm_ioremap_resource(dev, pmic->res); + if (!base) + return -ENOMEM; + + pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base, + &hi655x_regmap_config); + + regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver); + if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) { + dev_warn(dev, "PMU version %d unsupported\n", pmic->ver); + return -EINVAL; + } + + hi655x_local_irq_clear(pmic->regmap); + + pmic->gpio = of_get_named_gpio(np, "pmic-gpios", 0); + if (!gpio_is_valid(pmic->gpio)) { + dev_err(dev, "Failed to get the pmic-gpios\n"); + return -ENODEV; + } + + ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, + "hi655x_pmic_irq"); + if (ret < 0) { + dev_err(dev, "Failed to request gpio %d ret = %d\n", + pmic->gpio, ret); + return ret; + } + + ret = regmap_add_irq_chip(pmic->regmap, gpio_to_irq(pmic->gpio), + IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0, + &hi655x_irq_chip, &pmic->irq_data); + if (ret) { + dev_err(dev, "Failed to obtain 'hi655x_pmic_irq' %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, pmic); + + ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, hi655x_pmic_devs, + ARRAY_SIZE(hi655x_pmic_devs), NULL, 0, NULL); + if (ret) { + dev_err(dev, "Failed to register device %d\n", ret); + regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data); + return ret; + } + + return 0; +} + +static int hi655x_pmic_remove(struct platform_device *pdev) +{ + struct hi655x_pmic *pmic = platform_get_drvdata(pdev); + + regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data); + mfd_remove_devices(&pdev->dev); + return 0; +} + +static const struct of_device_id hi655x_pmic_match[] = { + { .compatible = "hisilicon,hi655x-pmic", }, + {}, +}; + +static struct platform_driver hi655x_pmic_driver = { + .driver = { + .name = "hi655x-pmic", + .of_match_table = of_match_ptr(hi655x_pmic_match), + }, + .probe = hi655x_pmic_probe, + .remove = hi655x_pmic_remove, +}; +module_platform_driver(hi655x_pmic_driver); + +MODULE_AUTHOR("Chen Feng "); +MODULE_DESCRIPTION("Hisilicon hi655x PMIC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/hi655x-pmic.h b/include/linux/mfd/hi655x-pmic.h new file mode 100644 index 000000000000..dbbe9a644622 --- /dev/null +++ b/include/linux/mfd/hi655x-pmic.h @@ -0,0 +1,55 @@ +/* + * Device driver for regulators in hi655x IC + * + * Copyright (c) 2016 Hisilicon. + * + * Authors: + * Chen Feng + * Fei Wang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __HI655X_PMIC_H +#define __HI655X_PMIC_H + +/* Hi655x registers are mapped to memory bus in 4 bytes stride */ +#define HI655X_STRIDE 4 +#define HI655X_BUS_ADDR(x) ((x) << 2) + +#define HI655X_BITS 8 + +#define HI655X_NR_IRQ 32 + +#define HI655X_IRQ_STAT_BASE (0x003 << 2) +#define HI655X_IRQ_MASK_BASE (0x007 << 2) +#define HI655X_ANA_IRQM_BASE (0x1b5 << 2) +#define HI655X_IRQ_ARRAY 4 +#define HI655X_IRQ_MASK 0xFF +#define HI655X_IRQ_CLR 0xFF +#define HI655X_VER_REG 0x00 + +#define PMU_VER_START 0x10 +#define PMU_VER_END 0x38 + +#define RESERVE_INT BIT(7) +#define PWRON_D20R_INT BIT(6) +#define PWRON_D20F_INT BIT(5) +#define PWRON_D4SR_INT BIT(4) +#define VSYS_6P0_D200UR_INT BIT(3) +#define VSYS_UV_D3R_INT BIT(2) +#define VSYS_2P5_R_INT BIT(1) +#define OTMP_D1R_INT BIT(0) + +struct hi655x_pmic { + struct resource *res; + struct device *dev; + struct regmap *regmap; + int gpio; + unsigned int ver; + struct regmap_irq_chip_data *irq_data; +}; + +#endif