From cfc95173ba8e18e41d9a69d2747d0f2738a2a551 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 23 Aug 2017 15:39:56 +0930 Subject: dt-bindings: aspeed-scu: Add clock and reset properties Signed-off-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/aspeed-scu.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/aspeed-scu.txt b/Documentation/devicetree/bindings/mfd/aspeed-scu.txt index 4fc5b83726d6..ce8cf0ec6279 100644 --- a/Documentation/devicetree/bindings/mfd/aspeed-scu.txt +++ b/Documentation/devicetree/bindings/mfd/aspeed-scu.txt @@ -9,10 +9,16 @@ Required properties: "aspeed,g5-scu", "syscon", "simple-mfd" - reg: contains the offset and length of the SCU memory region +- #clock-cells: should be set to <1> - the system controller is also a + clock provider +- #reset-cells: should be set to <1> - the system controller is also a + reset line provider Example: syscon: syscon@1e6e2000 { compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd"; reg = <0x1e6e2000 0x1a8>; + #clock-cells = <1>; + #reset-cells = <1>; }; -- cgit v1.2.3 From 511cb17448d95e4277451cdee882e72b6a9a3099 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 30 Aug 2017 14:59:10 +0530 Subject: mfd: tps65217: Introduce dependency on CONFIG_OF Currently the driver boots only via device tree hence add a dependency on CONFIG_OF. This leaves with a bunch of unused code so clean that up. This patch also makes use of probe_new function in place of the probe function so as to avoid passing i2c_device_id. Signed-off-by: Keerthy Reviewed-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- drivers/mfd/tps65217.c | 28 +++++----------------------- drivers/regulator/tps65217-regulator.c | 5 ----- drivers/video/backlight/tps65217_bl.c | 14 +++----------- include/linux/mfd/tps65217.h | 6 ------ 5 files changed, 9 insertions(+), 46 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fc5e4fef89d2..b47876877c9c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1338,7 +1338,7 @@ config MFD_TPS65090 config MFD_TPS65217 tristate "TI TPS65217 Power Management / White LED chips" - depends on I2C + depends on I2C && OF select MFD_CORE select REGMAP_I2C select IRQ_DOMAIN diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index f769c7d4e335..7566ce4457a0 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -311,37 +311,20 @@ static const struct regmap_config tps65217_regmap_config = { }; static const struct of_device_id tps65217_of_match[] = { - { .compatible = "ti,tps65217", .data = (void *)TPS65217 }, + { .compatible = "ti,tps65217"}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, tps65217_of_match); -static int tps65217_probe(struct i2c_client *client, - const struct i2c_device_id *ids) +static int tps65217_probe(struct i2c_client *client) { struct tps65217 *tps; unsigned int version; - unsigned long chip_id = ids->driver_data; - const struct of_device_id *match; bool status_off = false; int ret; - if (client->dev.of_node) { - match = of_match_device(tps65217_of_match, &client->dev); - if (!match) { - dev_err(&client->dev, - "Failed to find matching dt id\n"); - return -EINVAL; - } - chip_id = (unsigned long)match->data; - status_off = of_property_read_bool(client->dev.of_node, - "ti,pmic-shutdown-controller"); - } - - if (!chip_id) { - dev_err(&client->dev, "id is null.\n"); - return -ENODEV; - } + status_off = of_property_read_bool(client->dev.of_node, + "ti,pmic-shutdown-controller"); tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) @@ -349,7 +332,6 @@ static int tps65217_probe(struct i2c_client *client, i2c_set_clientdata(client, tps); tps->dev = &client->dev; - tps->id = chip_id; tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); if (IS_ERR(tps->regmap)) { @@ -430,7 +412,7 @@ static struct i2c_driver tps65217_driver = { .of_match_table = tps65217_of_match, }, .id_table = tps65217_id_table, - .probe = tps65217_probe, + .probe_new = tps65217_probe, .remove = tps65217_remove, }; diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 5324dc9e6d6e..7b12e880d1ea 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -228,11 +228,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) int i, ret; unsigned int val; - if (tps65217_chip_id(tps) != TPS65217) { - dev_err(&pdev->dev, "Invalid tps chip version\n"); - return -ENODEV; - } - /* Allocate memory for strobes */ tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * TPS65217_NUM_REGULATOR, GFP_KERNEL); diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index fd524ad860a5..5ce8791f4523 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -275,17 +275,9 @@ static int tps65217_bl_probe(struct platform_device *pdev) struct tps65217_bl_pdata *pdata; struct backlight_properties bl_props; - if (tps->dev->of_node) { - pdata = tps65217_bl_parse_dt(pdev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - } else { - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data provided\n"); - return -EINVAL; - } - } + pdata = tps65217_bl_parse_dt(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), GFP_KERNEL); diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index eac285756b37..b5dd108421c8 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -263,7 +263,6 @@ struct tps65217_board { struct tps65217 { struct device *dev; struct tps65217_board *pdata; - unsigned long id; struct regulator_desc desc[TPS65217_NUM_REGULATOR]; struct regmap *regmap; u8 *strobes; @@ -278,11 +277,6 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev) return dev_get_drvdata(dev); } -static inline unsigned long tps65217_chip_id(struct tps65217 *tps65217) -{ - return tps65217->id; -} - int tps65217_reg_read(struct tps65217 *tps, unsigned int reg, unsigned int *val); int tps65217_reg_write(struct tps65217 *tps, unsigned int reg, -- cgit v1.2.3 From 223fd9f61f84ee4dd08fb859f2de3f70cc3879f1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Sep 2017 12:27:12 +0100 Subject: mfd: stw481x: Make three arrays static const, reduces object code size Don't populate the arrays vcore_val, vpll_val and vaux_val on the stack, instead make them static const. Makes the object code smaller by over 370 bytes: Before: text data bss dec hex filename 6971 3248 64 10283 282b drivers/mfd/stw481x.o After: text data bss dec hex filename 6338 3504 64 9906 26b2 drivers/mfd/stw481x.o Signed-off-by: Colin Ian King Signed-off-by: Lee Jones --- drivers/mfd/stw481x.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/stw481x.c b/drivers/mfd/stw481x.c index ab949eaca6ad..3cc80956260e 100644 --- a/drivers/mfd/stw481x.c +++ b/drivers/mfd/stw481x.c @@ -72,10 +72,12 @@ static int stw481x_get_pctl_reg(struct stw481x *stw481x, u8 reg) static int stw481x_startup(struct stw481x *stw481x) { /* Voltages multiplied by 100 */ - u8 vcore_val[] = { 100, 105, 110, 115, 120, 122, 124, 126, 128, - 130, 132, 134, 136, 138, 140, 145 }; - u8 vpll_val[] = { 105, 120, 130, 180 }; - u8 vaux_val[] = { 15, 18, 25, 28 }; + static const u8 vcore_val[] = { + 100, 105, 110, 115, 120, 122, 124, 126, 128, + 130, 132, 134, 136, 138, 140, 145 + }; + static const u8 vpll_val[] = { 105, 120, 130, 180 }; + static const u8 vaux_val[] = { 15, 18, 25, 28 }; u8 vcore; u8 vcore_slp; u8 vpll; -- cgit v1.2.3 From 4589515af30005a404bd34e4b7933f98e68849f4 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Tue, 5 Sep 2017 15:50:27 +0200 Subject: mfd: max77693: Add muic of_compatible in mfd_cell This patch adds muic of_compatible in order to use the muic device driver in device tree. Signed-off-by: Maciej Purski Reviewed-by: Chanwoo Choi Reviewed-by: Krzysztof Kozlowski Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/max77693.txt | 6 ++++++ drivers/mfd/max77693.c | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt index 6a1ae3a2b77f..e6754974a745 100644 --- a/Documentation/devicetree/bindings/mfd/max77693.txt +++ b/Documentation/devicetree/bindings/mfd/max77693.txt @@ -127,6 +127,12 @@ Required properties for the LED child node: Optional properties for the LED child node: - label : see Documentation/devicetree/bindings/leds/common.txt +Optional nodes: +- max77693-muic : + Node used only by extcon consumers. + Required properties: + - compatible : "maxim,max77693-muic" + Example: #include diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 662ae0d9e334..1c05ea0cba61 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -48,7 +48,10 @@ static const struct mfd_cell max77693_devs[] = { .name = "max77693-charger", .of_compatible = "maxim,max77693-charger", }, - { .name = "max77693-muic", }, + { + .name = "max77693-muic", + .of_compatible = "maxim,max77693-muic", + }, { .name = "max77693-haptic", .of_compatible = "maxim,max77693-haptic", -- cgit v1.2.3 From 58ab243ef5ad1aee7600eb4bd8d9ce5a63401c5e Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Wed, 6 Sep 2017 17:27:41 -0700 Subject: syscon: dt-bindings: Add binding doc for Broadcom iProc CDRU Add binding document for Broadcom iProc's Chip Device Resource Unit (CDRU). Multiple iProc based chips have this CDRU block that contains miscellaneous registers for chip or device configurations. Start with Stingray specific compatible string for the initial binding Signed-off-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/brcm,iproc-cdru.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/brcm,iproc-cdru.txt diff --git a/Documentation/devicetree/bindings/mfd/brcm,iproc-cdru.txt b/Documentation/devicetree/bindings/mfd/brcm,iproc-cdru.txt new file mode 100644 index 000000000000..82f82e069563 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/brcm,iproc-cdru.txt @@ -0,0 +1,16 @@ +Broadcom iProc Chip Device Resource Unit (CDRU) + +Various Broadcom iProc SoCs have a set of registers that provide various +chip specific device and resource configurations. This node allows access to +these CDRU registers via syscon. + +Required properties: +- compatible: should contain: + "brcm,sr-cdru", "syscon" for Stingray +- reg: base address and range of the CDRU registers + +Example: + cdru: syscon@6641d000 { + compatible = "brcm,sr-cdru", "syscon"; + reg = <0 0x6641d000 0 0x400>; + }; -- cgit v1.2.3 From 88decb026d90c386b2a15adbe6fb094f6a86d144 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Wed, 6 Sep 2017 17:27:42 -0700 Subject: syscon: dt-bindings: Add binding document for iProc MHB block Add binding document for Broadcom iProc's Multi-Host Bridge (MHB) block Signed-off-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/brcm,iproc-mhb.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/brcm,iproc-mhb.txt diff --git a/Documentation/devicetree/bindings/mfd/brcm,iproc-mhb.txt b/Documentation/devicetree/bindings/mfd/brcm,iproc-mhb.txt new file mode 100644 index 000000000000..4421e9771b8a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/brcm,iproc-mhb.txt @@ -0,0 +1,18 @@ +Broadcom iProc Multi Host Bridge (MHB) + +Certain Broadcom iProc SoCs have a multi host bridge (MHB) block that controls +the connection and configuration of 1) internal PCIe serdes; 2) PCIe endpoint +interface; 3) access to the Nitro (network processing) engine + +This node allows access to these MHB registers via syscon. + +Required properties: +- compatible: should contain: + "brcm,sr-mhb", "syscon" for Stingray +- reg: base address and range of the MHB registers + +Example: + mhb: syscon@60401000 { + compatible = "brcm,sr-mhb", "syscon"; + reg = <0 0x60401000 0 0x38c>; + }; -- cgit v1.2.3 From 6bac0606fdba97a2666bc8f0460a05fb7352b7e2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Sep 2017 16:43:38 +0200 Subject: mfd: Add support for Cherry Trail Dollar Cove TI PMIC This patch adds the MFD driver for Dollar Cove (TI version) PMIC with ACPI INT33F5 that is found on some Intel Cherry Trail devices. The driver is based on the original work by Intel, found at: https://github.com/01org/ProductionKernelQuilts This is a minimal version for adding the basic resources. Currently, only ACPI PMIC opregion and the external power-button are used. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=193891 Signed-off-by: Takashi Iwai Reviewed-by: Mika Westerberg Reviewed-by: Andy Shevchenko Acked-by: Rafael J. Wysocki Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 13 +++ drivers/mfd/Makefile | 1 + drivers/mfd/intel_soc_pmic_chtdc_ti.c | 184 ++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/mfd/intel_soc_pmic_chtdc_ti.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b47876877c9c..47c2418dc662 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -510,6 +510,19 @@ config INTEL_SOC_PMIC_CHTWC available before any devices using it are probed. This option also causes the designware-i2c driver to be builtin for the same reason. +config INTEL_SOC_PMIC_CHTDC_TI + tristate "Support for Intel Cherry Trail Dollar Cove TI PMIC" + depends on GPIOLIB + depends on I2C + depends on ACPI + depends on X86 + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + Select this option for supporting Dollar Cove (TI version) PMIC + device that is found on some Intel Cherry Trail systems. + config MFD_INTEL_LPSS tristate select COMMON_CLK diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c3d0a1b39bb6..5d26f4064588 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -218,6 +218,7 @@ intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o +obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o diff --git a/drivers/mfd/intel_soc_pmic_chtdc_ti.c b/drivers/mfd/intel_soc_pmic_chtdc_ti.c new file mode 100644 index 000000000000..861277c6580a --- /dev/null +++ b/drivers/mfd/intel_soc_pmic_chtdc_ti.c @@ -0,0 +1,184 @@ +/* + * Device access for Dollar Cove TI PMIC + * + * Copyright (c) 2014, Intel Corporation. + * Author: Ramakrishna Pallala + * + * Cleanup and forward-ported + * Copyright (c) 2017 Takashi Iwai + * + * 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 + +#define CHTDC_TI_IRQLVL1 0x01 +#define CHTDC_TI_MASK_IRQLVL1 0x02 + +/* Level 1 IRQs */ +enum { + CHTDC_TI_PWRBTN = 0, /* power button */ + CHTDC_TI_DIETMPWARN, /* thermal */ + CHTDC_TI_ADCCMPL, /* ADC */ + /* No IRQ 3 */ + CHTDC_TI_VBATLOW = 4, /* battery */ + CHTDC_TI_VBUSDET, /* power source */ + /* No IRQ 6 */ + CHTDC_TI_CCEOCAL = 7, /* battery */ +}; + +static struct resource power_button_resources[] = { + DEFINE_RES_IRQ(CHTDC_TI_PWRBTN), +}; + +static struct resource thermal_resources[] = { + DEFINE_RES_IRQ(CHTDC_TI_DIETMPWARN), +}; + +static struct resource adc_resources[] = { + DEFINE_RES_IRQ(CHTDC_TI_ADCCMPL), +}; + +static struct resource pwrsrc_resources[] = { + DEFINE_RES_IRQ(CHTDC_TI_VBUSDET), +}; + +static struct resource battery_resources[] = { + DEFINE_RES_IRQ(CHTDC_TI_VBATLOW), + DEFINE_RES_IRQ(CHTDC_TI_CCEOCAL), +}; + +static struct mfd_cell chtdc_ti_dev[] = { + { + .name = "chtdc_ti_pwrbtn", + .num_resources = ARRAY_SIZE(power_button_resources), + .resources = power_button_resources, + }, { + .name = "chtdc_ti_adc", + .num_resources = ARRAY_SIZE(adc_resources), + .resources = adc_resources, + }, { + .name = "chtdc_ti_thermal", + .num_resources = ARRAY_SIZE(thermal_resources), + .resources = thermal_resources, + }, { + .name = "chtdc_ti_pwrsrc", + .num_resources = ARRAY_SIZE(pwrsrc_resources), + .resources = pwrsrc_resources, + }, { + .name = "chtdc_ti_battery", + .num_resources = ARRAY_SIZE(battery_resources), + .resources = battery_resources, + }, + { .name = "chtdc_ti_region", }, +}; + +static const struct regmap_config chtdc_ti_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 128, + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_irq chtdc_ti_irqs[] = { + REGMAP_IRQ_REG(CHTDC_TI_PWRBTN, 0, BIT(CHTDC_TI_PWRBTN)), + REGMAP_IRQ_REG(CHTDC_TI_DIETMPWARN, 0, BIT(CHTDC_TI_DIETMPWARN)), + REGMAP_IRQ_REG(CHTDC_TI_ADCCMPL, 0, BIT(CHTDC_TI_ADCCMPL)), + REGMAP_IRQ_REG(CHTDC_TI_VBATLOW, 0, BIT(CHTDC_TI_VBATLOW)), + REGMAP_IRQ_REG(CHTDC_TI_VBUSDET, 0, BIT(CHTDC_TI_VBUSDET)), + REGMAP_IRQ_REG(CHTDC_TI_CCEOCAL, 0, BIT(CHTDC_TI_CCEOCAL)), +}; + +static const struct regmap_irq_chip chtdc_ti_irq_chip = { + .name = KBUILD_MODNAME, + .irqs = chtdc_ti_irqs, + .num_irqs = ARRAY_SIZE(chtdc_ti_irqs), + .num_regs = 1, + .status_base = CHTDC_TI_IRQLVL1, + .mask_base = CHTDC_TI_MASK_IRQLVL1, + .ack_base = CHTDC_TI_IRQLVL1, +}; + +static int chtdc_ti_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct intel_soc_pmic *pmic; + int ret; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + i2c_set_clientdata(i2c, pmic); + + pmic->regmap = devm_regmap_init_i2c(i2c, &chtdc_ti_regmap_config); + if (IS_ERR(pmic->regmap)) + return PTR_ERR(pmic->regmap); + pmic->irq = i2c->irq; + + ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, + IRQF_ONESHOT, 0, + &chtdc_ti_irq_chip, + &pmic->irq_chip_data); + if (ret) + return ret; + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, chtdc_ti_dev, + ARRAY_SIZE(chtdc_ti_dev), NULL, 0, + regmap_irq_get_domain(pmic->irq_chip_data)); +} + +static void chtdc_ti_shutdown(struct i2c_client *i2c) +{ + struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c); + + disable_irq(pmic->irq); +} + +static int __maybe_unused chtdc_ti_suspend(struct device *dev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + disable_irq(pmic->irq); + + return 0; +} + +static int __maybe_unused chtdc_ti_resume(struct device *dev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + enable_irq(pmic->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(chtdc_ti_pm_ops, chtdc_ti_suspend, chtdc_ti_resume); + +static const struct acpi_device_id chtdc_ti_acpi_ids[] = { + { "INT33F5" }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, chtdc_ti_acpi_ids); + +static struct i2c_driver chtdc_ti_i2c_driver = { + .driver = { + .name = "intel_soc_pmic_chtdc_ti", + .pm = &chtdc_ti_pm_ops, + .acpi_match_table = chtdc_ti_acpi_ids, + }, + .probe_new = chtdc_ti_probe, + .shutdown = chtdc_ti_shutdown, +}; +module_i2c_driver(chtdc_ti_i2c_driver); + +MODULE_DESCRIPTION("I2C driver for Intel SoC Dollar Cove TI PMIC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 31374972321d1639d1a8bb1213b66688132d103f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Sep 2017 16:43:40 +0200 Subject: ACPI / PMIC: Add opregion driver for Intel Dollar Cove TI PMIC This patch adds the opregion driver for Dollar Cove TI PMIC on Intel Cherry Trail devices. The patch is based on the original work by Intel, found at: https://github.com/01org/ProductionKernelQuilts with many cleanups and rewrites. The driver is currently provided only as built-in to follow other PMIC opregion drivers convention. The re-enumeration of devices at probe is required for fixing the issues on HP x2 210 G2. See bug#195689. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=193891 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195689 Signed-off-by: Takashi Iwai Reviewed-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/acpi/Kconfig | 6 ++ drivers/acpi/Makefile | 1 + drivers/acpi/pmic/intel_pmic_chtdc_ti.c | 137 ++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 drivers/acpi/pmic/intel_pmic_chtdc_ti.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 1ce52f84dc23..176fae699891 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -521,6 +521,12 @@ config CHT_WC_PMIC_OPREGION help This config adds ACPI operation region support for CHT Whiskey Cove PMIC. +config CHT_DC_TI_PMIC_OPREGION + bool "ACPI operation region support for Dollar Cove TI PMIC" + depends on INTEL_SOC_PMIC_CHTDC_TI + help + This config adds ACPI operation region support for Dollar Cove TI PMIC. + endif config ACPI_CONFIGFS diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 90265ab4437a..21185613bc9b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -104,6 +104,7 @@ obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o +obj-$(CONFIG_CHT_DC_TI_PMIC_OPREGION) += pmic/intel_pmic_chtdc_ti.o obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c new file mode 100644 index 000000000000..109c1e9c9c7a --- /dev/null +++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c @@ -0,0 +1,137 @@ +/* + * Dollar Cove TI PMIC operation region driver + * Copyright (C) 2014 Intel Corporation. All rights reserved. + * + * Rewritten and cleaned up + * Copyright (C) 2017 Takashi Iwai + */ + +#include +#include +#include +#include +#include "intel_pmic.h" + +/* registers stored in 16bit BE (high:low, total 10bit) */ +#define CHTDC_TI_VBAT 0x54 +#define CHTDC_TI_DIETEMP 0x56 +#define CHTDC_TI_BPTHERM 0x58 +#define CHTDC_TI_GPADC 0x5a + +static struct pmic_table chtdc_ti_power_table[] = { + { .address = 0x00, .reg = 0x41 }, + { .address = 0x04, .reg = 0x42 }, + { .address = 0x08, .reg = 0x43 }, + { .address = 0x0c, .reg = 0x45 }, + { .address = 0x10, .reg = 0x46 }, + { .address = 0x14, .reg = 0x47 }, + { .address = 0x18, .reg = 0x48 }, + { .address = 0x1c, .reg = 0x49 }, + { .address = 0x20, .reg = 0x4a }, + { .address = 0x24, .reg = 0x4b }, + { .address = 0x28, .reg = 0x4c }, + { .address = 0x2c, .reg = 0x4d }, + { .address = 0x30, .reg = 0x4e }, +}; + +static struct pmic_table chtdc_ti_thermal_table[] = { + { + .address = 0x00, + .reg = CHTDC_TI_GPADC + }, + { + .address = 0x0c, + .reg = CHTDC_TI_GPADC + }, + /* TMP2 -> SYSTEMP */ + { + .address = 0x18, + .reg = CHTDC_TI_GPADC + }, + /* TMP3 -> BPTHERM */ + { + .address = 0x24, + .reg = CHTDC_TI_BPTHERM + }, + { + .address = 0x30, + .reg = CHTDC_TI_GPADC + }, + /* TMP5 -> DIETEMP */ + { + .address = 0x3c, + .reg = CHTDC_TI_DIETEMP + }, +}; + +static int chtdc_ti_pmic_get_power(struct regmap *regmap, int reg, int bit, + u64 *value) +{ + int data; + + if (regmap_read(regmap, reg, &data)) + return -EIO; + + *value = data & 1; + return 0; +} + +static int chtdc_ti_pmic_update_power(struct regmap *regmap, int reg, int bit, + bool on) +{ + return regmap_update_bits(regmap, reg, 1, on); +} + +static int chtdc_ti_pmic_get_raw_temp(struct regmap *regmap, int reg) +{ + u8 buf[2]; + + if (regmap_bulk_read(regmap, reg, buf, 2)) + return -EIO; + + /* stored in big-endian */ + return ((buf[0] & 0x03) << 8) | buf[1]; +} + +static struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = { + .get_power = chtdc_ti_pmic_get_power, + .update_power = chtdc_ti_pmic_update_power, + .get_raw_temp = chtdc_ti_pmic_get_raw_temp, + .power_table = chtdc_ti_power_table, + .power_table_count = ARRAY_SIZE(chtdc_ti_power_table), + .thermal_table = chtdc_ti_thermal_table, + .thermal_table_count = ARRAY_SIZE(chtdc_ti_thermal_table), +}; + +static int chtdc_ti_pmic_opregion_probe(struct platform_device *pdev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); + int err; + + err = intel_pmic_install_opregion_handler(&pdev->dev, + ACPI_HANDLE(pdev->dev.parent), pmic->regmap, + &chtdc_ti_pmic_opregion_data); + if (err < 0) + return err; + + /* Re-enumerate devices depending on PMIC */ + acpi_walk_dep_device_list(ACPI_HANDLE(pdev->dev.parent)); + return 0; +} + +static const struct platform_device_id chtdc_ti_pmic_opregion_id_table[] = { + { .name = "chtdc_ti_region" }, + {}, +}; + +static struct platform_driver chtdc_ti_pmic_opregion_driver = { + .probe = chtdc_ti_pmic_opregion_probe, + .driver = { + .name = "cht_dollar_cove_ti_pmic", + }, + .id_table = chtdc_ti_pmic_opregion_id_table, +}; +module_platform_driver(chtdc_ti_pmic_opregion_driver); + +MODULE_DESCRIPTION("Dollar Cove TI PMIC opregion driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8275b77a15131673f955f738f0704e1d40a8edae Mon Sep 17 00:00:00 2001 From: Rui Feng Date: Thu, 7 Sep 2017 16:26:39 +0800 Subject: mfd: rts5249: Add support for RTS5250S power saving Enable power saving for RTS5250S as following steps: 1.Set 0xFE58 to enable clock power management. 2.Check cfg space whether support L1SS or not. 3.If support L1SS, set 0xFF03 to free clkreq. 4.When entering idle status, enable aspm and set parameters for L1SS and LTR. 5.Wnen entering run status, disable aspm and set parameters for L1SS and LTR. If entering L1SS mode successfully, electric current will be below 2mA. Signed-off-by: Rui Feng Signed-off-by: Lee Jones --- drivers/mfd/rts5249.c | 155 ++++++++++++++++++++++++++++++++++++++++++- drivers/mfd/rtsx_pcr.c | 142 +++++++++++++++++++++++++++++++++++++-- drivers/mfd/rtsx_pcr.h | 14 ++++ include/linux/mfd/rtsx_pci.h | 84 +++++++++++++++++++++++ 4 files changed, 389 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index 40f8bb14fc59..7fcf37ba922c 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -103,8 +103,64 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); } +static void rts5249_init_from_cfg(struct rtsx_pcr *pcr) +{ + struct rtsx_cr_option *option = &(pcr->option); + u32 lval; + + if (CHK_PCI_PID(pcr, PID_524A)) + rtsx_pci_read_config_dword(pcr, + PCR_ASPM_SETTING_REG1, &lval); + else + rtsx_pci_read_config_dword(pcr, + PCR_ASPM_SETTING_REG2, &lval); + + if (lval & ASPM_L1_1_EN_MASK) + rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); + + if (lval & ASPM_L1_2_EN_MASK) + rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); + + if (lval & PM_L1_1_EN_MASK) + rtsx_set_dev_flag(pcr, PM_L1_1_EN); + + if (lval & PM_L1_2_EN_MASK) + rtsx_set_dev_flag(pcr, PM_L1_2_EN); + + if (option->ltr_en) { + u16 val; + + pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val); + if (val & PCI_EXP_DEVCTL2_LTR_EN) { + option->ltr_enabled = true; + option->ltr_active = true; + rtsx_set_ltr_latency(pcr, option->ltr_active_latency); + } else { + option->ltr_enabled = false; + } + } +} + +static int rts5249_init_from_hw(struct rtsx_pcr *pcr) +{ + struct rtsx_cr_option *option = &(pcr->option); + + if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN + | PM_L1_1_EN | PM_L1_2_EN)) + option->force_clkreq_0 = false; + else + option->force_clkreq_0 = true; + + return 0; +} + static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) { + struct rtsx_cr_option *option = &(pcr->option); + + rts5249_init_from_cfg(pcr); + rts5249_init_from_hw(pcr); + rtsx_pci_init_cmd(pcr); /* Rest L1SUB Config */ @@ -125,7 +181,18 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80); - return rtsx_pci_send_cmd(pcr, 100); + /* + * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced + * to drive low, and we forcibly request clock. + */ + if (option->force_clkreq_0) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); + + return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF); } static int rts5249_optimize_phy(struct rtsx_pcr *pcr) @@ -285,6 +352,31 @@ static int rtsx_base_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) return rtsx_pci_send_cmd(pcr, 100); } +static void rts5249_set_aspm(struct rtsx_pcr *pcr, bool enable) +{ + struct rtsx_cr_option *option = &pcr->option; + u8 val = 0; + + if (pcr->aspm_enabled == enable) + return; + + if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) { + if (enable) + val = pcr->aspm_en; + rtsx_pci_update_cfg_byte(pcr, + pcr->pcie_cap + PCI_EXP_LNKCTL, + ASPM_MASK_NEG, val); + } else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) { + u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0; + + if (!enable) + val = FORCE_ASPM_CTL0; + rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val); + } + + pcr->aspm_enabled = enable; +} + static const struct pcr_ops rts5249_pcr_ops = { .fetch_vendor_settings = rtsx_base_fetch_vendor_settings, .extra_init_hw = rts5249_extra_init_hw, @@ -297,6 +389,7 @@ static const struct pcr_ops rts5249_pcr_ops = { .card_power_off = rtsx_base_card_power_off, .switch_output_voltage = rtsx_base_switch_output_voltage, .force_power_down = rtsx_base_force_power_down, + .set_aspm = rts5249_set_aspm, }; /* SD Pull Control Enable: @@ -353,6 +446,8 @@ static const u32 rts5249_ms_pull_ctl_disable_tbl[] = { void rts5249_init_params(struct rtsx_pcr *pcr) { + struct rtsx_cr_option *option = &(pcr->option); + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; pcr->num_slots = 2; pcr->ops = &rts5249_pcr_ops; @@ -372,6 +467,20 @@ void rts5249_init_params(struct rtsx_pcr *pcr) pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl; pcr->reg_pm_ctrl3 = PM_CTRL3; + + option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN + | LTR_L1SS_PWR_GATE_EN); + option->ltr_en = true; + + /* Init latency of active, idle, L1OFF to 60us, 300us, 3ms */ + option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF; + option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF; + option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF; + option->dev_aspm_mode = DEV_ASPM_DYNAMIC; + option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF; + option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF; + option->ltr_l1off_snooze_sspwrgate = + LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF; } static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val) @@ -459,6 +568,40 @@ static int rts524a_extra_init_hw(struct rtsx_pcr *pcr) return 0; } +static void rts5250_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active) +{ + struct rtsx_cr_option *option = &(pcr->option); + + u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR); + int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST); + int aspm_L1_1, aspm_L1_2; + u8 val = 0; + + aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN); + aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN); + + if (active) { + /* Run, latency: 60us */ + if (aspm_L1_1) + val = option->ltr_l1off_snooze_sspwrgate; + } else { + /* L1off, latency: 300us */ + if (aspm_L1_2) + val = option->ltr_l1off_sspwrgate; + } + + if (aspm_L1_1 || aspm_L1_2) { + if (rtsx_check_dev_flag(pcr, + LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) { + if (card_exist) + val &= ~L1OFF_MBIAS2_EN_5250; + else + val |= L1OFF_MBIAS2_EN_5250; + } + } + rtsx_set_l1off_sub(pcr, val); +} + static const struct pcr_ops rts524a_pcr_ops = { .write_phy = rts524a_write_phy, .read_phy = rts524a_read_phy, @@ -473,11 +616,16 @@ static const struct pcr_ops rts524a_pcr_ops = { .card_power_off = rtsx_base_card_power_off, .switch_output_voltage = rtsx_base_switch_output_voltage, .force_power_down = rtsx_base_force_power_down, + .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0, + .set_aspm = rts5249_set_aspm, }; void rts524a_init_params(struct rtsx_pcr *pcr) { rts5249_init_params(pcr); + pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF; + pcr->option.ltr_l1off_snooze_sspwrgate = + LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF; pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3; pcr->ops = &rts524a_pcr_ops; @@ -576,11 +724,16 @@ static const struct pcr_ops rts525a_pcr_ops = { .card_power_off = rtsx_base_card_power_off, .switch_output_voltage = rts525a_switch_output_voltage, .force_power_down = rtsx_base_force_power_down, + .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0, + .set_aspm = rts5249_set_aspm, }; void rts525a_init_params(struct rtsx_pcr *pcr) { rts5249_init_params(pcr); + pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF; + pcr->option.ltr_l1off_snooze_sspwrgate = + LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF; pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3; pcr->ops = &rts525a_pcr_ops; diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 3cf69e5c5703..590fb9aad77d 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -79,6 +79,96 @@ static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr) 0xFC, 0); } +int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) +{ + rtsx_pci_write_register(pcr, MSGTXDATA0, + MASK_8_BIT_DEF, (u8) (latency & 0xFF)); + rtsx_pci_write_register(pcr, MSGTXDATA1, + MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF)); + rtsx_pci_write_register(pcr, MSGTXDATA2, + MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF)); + rtsx_pci_write_register(pcr, MSGTXDATA3, + MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF)); + rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK | + LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW); + + return 0; +} + +int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) +{ + if (pcr->ops->set_ltr_latency) + return pcr->ops->set_ltr_latency(pcr, latency); + else + return rtsx_comm_set_ltr_latency(pcr, latency); +} + +static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable) +{ + struct rtsx_cr_option *option = &pcr->option; + + if (pcr->aspm_enabled == enable) + return; + + if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) { + if (enable) + rtsx_pci_enable_aspm(pcr); + else + rtsx_pci_disable_aspm(pcr); + } else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) { + u8 mask = FORCE_ASPM_VAL_MASK; + u8 val = 0; + + if (enable) + val = pcr->aspm_en; + rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val); + } + + pcr->aspm_enabled = enable; +} + +static void rtsx_disable_aspm(struct rtsx_pcr *pcr) +{ + if (pcr->ops->set_aspm) + pcr->ops->set_aspm(pcr, false); + else + rtsx_comm_set_aspm(pcr, false); +} + +int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val) +{ + rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val); + + return 0; +} + +void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active) +{ + if (pcr->ops->set_l1off_cfg_sub_d0) + pcr->ops->set_l1off_cfg_sub_d0(pcr, active); +} + +static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr) +{ + struct rtsx_cr_option *option = &pcr->option; + + rtsx_disable_aspm(pcr); + + if (option->ltr_enabled) + rtsx_set_ltr_latency(pcr, option->ltr_active_latency); + + if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) + rtsx_set_l1off_sub_cfg_d0(pcr, 1); +} + +void rtsx_pm_full_on(struct rtsx_pcr *pcr) +{ + if (pcr->ops->full_on) + pcr->ops->full_on(pcr); + else + rtsx_comm_pm_full_on(pcr); +} + void rtsx_pci_start_run(struct rtsx_pcr *pcr) { /* If pci device removed, don't queue idle work any more */ @@ -89,9 +179,7 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr) pcr->state = PDEV_STAT_RUN; if (pcr->ops->enable_auto_blink) pcr->ops->enable_auto_blink(pcr); - - if (pcr->aspm_en) - rtsx_pci_disable_aspm(pcr); + rtsx_pm_full_on(pcr); } mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); @@ -958,6 +1046,41 @@ static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) return 0; } +static void rtsx_enable_aspm(struct rtsx_pcr *pcr) +{ + if (pcr->ops->set_aspm) + pcr->ops->set_aspm(pcr, true); + else + rtsx_comm_set_aspm(pcr, true); +} + +static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr) +{ + struct rtsx_cr_option *option = &pcr->option; + + if (option->ltr_enabled) { + u32 latency = option->ltr_l1off_latency; + + if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN)) + mdelay(option->l1_snooze_delay); + + rtsx_set_ltr_latency(pcr, latency); + } + + if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) + rtsx_set_l1off_sub_cfg_d0(pcr, 0); + + rtsx_enable_aspm(pcr); +} + +void rtsx_pm_power_saving(struct rtsx_pcr *pcr) +{ + if (pcr->ops->power_saving) + pcr->ops->power_saving(pcr); + else + rtsx_comm_pm_power_saving(pcr); +} + static void rtsx_pci_idle_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -974,8 +1097,7 @@ static void rtsx_pci_idle_work(struct work_struct *work) if (pcr->ops->turn_off_led) pcr->ops->turn_off_led(pcr); - if (pcr->aspm_en) - rtsx_pci_enable_aspm(pcr); + rtsx_pm_power_saving(pcr); mutex_unlock(&pcr->pcr_mutex); } @@ -1063,6 +1185,16 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) if (err < 0) return err; + switch (PCI_PID(pcr)) { + case PID_5250: + case PID_524A: + case PID_525A: + rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1); + break; + default: + break; + } + /* Enable clk_request_n to enable clock power management */ rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1); /* Enter L1 when host tx idle */ diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index 931d1ae3ce32..ec784e04fe20 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h @@ -32,6 +32,18 @@ #define RTS524A_PME_FORCE_CTL 0xFF78 #define RTS524A_PM_CTRL3 0xFF7E +#define LTR_ACTIVE_LATENCY_DEF 0x883C +#define LTR_IDLE_LATENCY_DEF 0x892C +#define LTR_L1OFF_LATENCY_DEF 0x9003 +#define L1_SNOOZE_DELAY_DEF 1 +#define LTR_L1OFF_SSPWRGATE_5249_DEF 0xAF +#define LTR_L1OFF_SSPWRGATE_5250_DEF 0xFF +#define LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF 0xAC +#define LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF 0xF8 +#define CMD_TIMEOUT_DEF 100 +#define ASPM_MASK_NEG 0xFC +#define MASK_8_BIT_DEF 0xFF + int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val); int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val); @@ -85,5 +97,7 @@ do { \ /* generic operations */ int rtsx_gops_pm_reset(struct rtsx_pcr *pcr); +int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency); +int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val); #endif diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 116816fb9110..57e23ad1c2bc 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -573,6 +573,12 @@ #define MSGTXDATA3 0xFE47 #define MSGTXCTL 0xFE48 #define LTR_CTL 0xFE4A +#define LTR_TX_EN_MASK BIT(7) +#define LTR_TX_EN_1 BIT(7) +#define LTR_TX_EN_0 0 +#define LTR_LATENCY_MODE_MASK BIT(6) +#define LTR_LATENCY_MODE_HW 0 +#define LTR_LATENCY_MODE_SW BIT(6) #define OBFF_CFG 0xFE4C #define CDRESUMECTL 0xFE52 @@ -616,11 +622,15 @@ #define L1SUB_CONFIG2 0xFE8E #define L1SUB_AUTO_CFG 0x02 #define L1SUB_CONFIG3 0xFE8F +#define L1OFF_MBIAS2_EN_5250 BIT(7) #define DUMMY_REG_RESET_0 0xFE90 #define AUTOLOAD_CFG_BASE 0xFF00 #define PETXCFG 0xFF03 +#define FORCE_CLKREQ_DELINK_MASK BIT(7) +#define FORCE_CLKREQ_LOW 0x80 +#define FORCE_CLKREQ_HIGH 0x00 #define PM_CTRL1 0xFF44 #define CD_RESUME_EN_MASK 0xF0 @@ -844,6 +854,9 @@ #define PHY_DIG1E_RX_EN_KEEP 0x0001 #define PHY_DUM_REG 0x1F +#define PCR_ASPM_SETTING_REG1 0x160 +#define PCR_ASPM_SETTING_REG2 0x168 + #define PCR_SETTING_REG1 0x724 #define PCR_SETTING_REG2 0x814 #define PCR_SETTING_REG3 0x747 @@ -876,14 +889,79 @@ struct pcr_ops { int (*conv_clk_and_div_n)(int clk, int dir); void (*fetch_vendor_settings)(struct rtsx_pcr *pcr); void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state); + + void (*set_aspm)(struct rtsx_pcr *pcr, bool enable); + int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency); + int (*set_l1off_sub)(struct rtsx_pcr *pcr, u8 val); + void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active); + void (*full_on)(struct rtsx_pcr *pcr); + void (*power_saving)(struct rtsx_pcr *pcr); }; enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; +#define ASPM_L1_1_EN_MASK BIT(3) +#define ASPM_L1_2_EN_MASK BIT(2) +#define PM_L1_1_EN_MASK BIT(1) +#define PM_L1_2_EN_MASK BIT(0) + +#define ASPM_L1_1_EN BIT(0) +#define ASPM_L1_2_EN BIT(1) +#define PM_L1_1_EN BIT(2) +#define PM_L1_2_EN BIT(3) +#define LTR_L1SS_PWR_GATE_EN BIT(4) +#define L1_SNOOZE_TEST_EN BIT(5) +#define LTR_L1SS_PWR_GATE_CHECK_CARD_EN BIT(6) + +enum dev_aspm_mode { + DEV_ASPM_DISABLE = 0, + DEV_ASPM_DYNAMIC, + DEV_ASPM_BACKDOOR, + DEV_ASPM_STATIC, +}; + +/* + * struct rtsx_cr_option - card reader option + * @dev_flags: device flags + * @force_clkreq_0: force clock request + * @ltr_en: enable ltr mode flag + * @ltr_enabled: ltr mode in configure space flag + * @ltr_active: ltr mode status + * @ltr_active_latency: ltr mode active latency + * @ltr_idle_latency: ltr mode idle latency + * @ltr_l1off_latency: ltr mode l1off latency + * @dev_aspm_mode: device aspm mode + * @l1_snooze_delay: l1 snooze delay + * @ltr_l1off_sspwrgate: ltr l1off sspwrgate + * @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate + */ +struct rtsx_cr_option { + u32 dev_flags; + bool force_clkreq_0; + bool ltr_en; + bool ltr_enabled; + bool ltr_active; + u32 ltr_active_latency; + u32 ltr_idle_latency; + u32 ltr_l1off_latency; + enum dev_aspm_mode dev_aspm_mode; + u32 l1_snooze_delay; + u8 ltr_l1off_sspwrgate; + u8 ltr_l1off_snooze_sspwrgate; +}; + +#define rtsx_set_dev_flag(cr, flag) \ + ((cr)->option.dev_flags |= (flag)) +#define rtsx_clear_dev_flag(cr, flag) \ + ((cr)->option.dev_flags &= ~(flag)) +#define rtsx_check_dev_flag(cr, flag) \ + ((cr)->option.dev_flags & (flag)) + struct rtsx_pcr { struct pci_dev *pci; unsigned int id; int pcie_cap; + struct rtsx_cr_option option; /* pci resources */ unsigned long addr; @@ -940,6 +1018,7 @@ struct rtsx_pcr { u8 card_drive_sel; #define ASPM_L1_EN 0x02 u8 aspm_en; + bool aspm_enabled; #define PCR_MS_PMOS (1 << 0) #define PCR_REVERSE_SOCKET (1 << 1) @@ -964,6 +1043,11 @@ struct rtsx_pcr { u8 dma_error_count; }; +#define PID_524A 0x524A +#define PID_5249 0x5249 +#define PID_5250 0x5250 +#define PID_525A 0x525A + #define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid)) #define PCI_VID(pcr) ((pcr)->pci->vendor) #define PCI_PID(pcr) ((pcr)->pci->device) -- cgit v1.2.3 From f132bc3f301efad6762d62a2aa2ad7b0caa8cbf0 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 12 Sep 2017 10:34:15 +0200 Subject: mfd: fsl-imx25: Set irq handler and data in one go Replace the two separate calls for setting the irq handler and data with a single irq_set_chained_handler_and_data() call. Signed-off-by: Martin Kaiser Signed-off-by: Lee Jones --- drivers/mfd/fsl-imx25-tsadc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index b3767c3141e5..14189efd70d0 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -84,8 +84,7 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev, return -ENOMEM; } - irq_set_chained_handler(irq, mx25_tsadc_irq_handler); - irq_set_handler_data(irq, tsadc); + irq_set_chained_handler_and_data(irq, mx25_tsadc_irq_handler, tsadc); return 0; } -- cgit v1.2.3 From 69075af67245c9a18d95028dd947135e85e08877 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Tue, 12 Sep 2017 10:14:28 +0100 Subject: MAINTAINERS: Fix Dialog search term for watchdog binding file Commit 340267640d769d3b3af9 ("MAINTAINERS: da9062/61 updates to the Dialog Semiconductor search terms") contained a typo for the watchdog binding: da92??-wdt.txt should have read da90??-wdt.txt. This new commit will fix the error and allows Dialog Semiconductor to follow files for PMIC bindings correctly. Signed-off-by: Steve Twiss Signed-off-by: Lee Jones --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2281af4b41b6..0f01a06ad448 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4103,7 +4103,7 @@ F: Documentation/devicetree/bindings/mfd/da90*.txt F: Documentation/devicetree/bindings/input/da90??-onkey.txt F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt F: Documentation/devicetree/bindings/regulator/da92*.txt -F: Documentation/devicetree/bindings/watchdog/da92??-wdt.txt +F: Documentation/devicetree/bindings/watchdog/da90??-wdt.txt F: Documentation/devicetree/bindings/sound/da[79]*.txt F: drivers/gpio/gpio-da90??.c F: drivers/hwmon/da90??-hwmon.c -- cgit v1.2.3 From 8f76af65a53cfee25c1a7eccbf8a180d7471657d Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 13 Sep 2017 17:47:09 +0530 Subject: mfd: tps65218: Correct the config description When the initial support was added for this PMIC was added only regulator support was present. Now we have GPIO and Powerbutton support as well. Hence correct the description of MFD_TPS65218 config option. Signed-off-by: Keerthy Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 47c2418dc662..c5bc48a4d7a0 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1421,8 +1421,7 @@ config MFD_TPS65218 If you say yes here you get support for the TPS65218 series of Power Management chips. These include voltage regulators, gpio and other features - that are often used in portable devices. Only regulator - component is currently supported. + that are often used in portable devices. This driver can also be built as a module. If so, the module will be called tps65218. -- cgit v1.2.3 From b2b3adc93e9e46554bedf26f2ee081126c2b8a22 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 13 Sep 2017 17:47:10 +0530 Subject: mfd: tps65218: Introduce dependency on CONFIG_OF Currently the driver boots only via device tree hence add a dependency on CONFIG_OF. This leaves with a bunch of unused code so clean that up. Signed-off-by: Keerthy Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- drivers/mfd/tps65218.c | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index c5bc48a4d7a0..5fecee6d972c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1413,7 +1413,7 @@ config MFD_TI_LP87565 config MFD_TPS65218 tristate "TI TPS65218 Power Management chips" - depends on I2C + depends on I2C && OF select MFD_CORE select REGMAP_I2C select REGMAP_IRQ diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 13834a0d2817..910f569ff77c 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -215,17 +215,9 @@ static int tps65218_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct tps65218 *tps; - const struct of_device_id *match; int ret; unsigned int chipid; - match = of_match_device(of_tps65218_match_table, &client->dev); - if (!match) { - dev_err(&client->dev, - "Failed to find matching dt id\n"); - return -EINVAL; - } - tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; -- cgit v1.2.3 From 07d70913dce59f3c8e5d0ca76250861158a9ca6c Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 11 Oct 2017 12:40:55 +0200 Subject: mfd: lpc_ich: Avoton/Rangeley uses SPI_BYT method Avoton/Rangeley are based on Silvermount micro-architecture, like Bay Trail, and uses the INTEL_SPI_BYT method to drive SPI. Cc: stable@vger.kernel.org Signed-off-by: Joakim Tjernlund Acked-by: Mika Westerberg Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 450ae36645aa..cf1120abbf52 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -522,6 +522,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { .name = "Avoton SoC", .iTCO_version = 3, .gpio_version = AVOTON_GPIO, + .spi_type = INTEL_SPI_BYT, }, [LPC_BAYTRAIL] = { .name = "Bay Trail SoC", -- cgit v1.2.3 From 362741a21a5c4b9ee31e75ce28d63c6d238a745c Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 14 Oct 2017 01:06:56 +0300 Subject: mfd: mxs-lradc: Fix error handling in mxs_lradc_probe() There is the only path, where mxs_lradc_probe() leaves clk undisabled, since it does return instead of goto err_clk. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Lee Jones --- drivers/mfd/mxs-lradc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c index 630bd19b2c0a..98e732a7ae96 100644 --- a/drivers/mfd/mxs-lradc.c +++ b/drivers/mfd/mxs-lradc.c @@ -196,8 +196,10 @@ static int mxs_lradc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, lradc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOMEM; + if (!res) { + ret = -ENOMEM; + goto err_clk; + } switch (lradc->soc) { case IMX23_LRADC: -- cgit v1.2.3 From 18f77393796848e68909e65d692c1d1436f06e06 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 17 Oct 2017 22:53:08 +0200 Subject: mfd: fsl-imx25: Clean up irq settings during removal When fsl-imx25-tsadc is compiled as a module, loading, unloading and reloading the module will lead to a crash. Unable to handle kernel paging request at virtual address bf005430 [] (irq_find_matching_fwspec) from [] (of_irq_get+0x58/0x74) [] (of_irq_get) from [] (platform_get_irq+0x48/0xc8) [] (platform_get_irq) from [] (mx25_tsadc_probe+0x220/0x2f4 [fsl_imx25_tsadc]) irq_find_matching_fwspec() loops over all registered irq domains. The irq domain is still registered from last time the module was loaded but the pointer to its operations is invalid after the module was unloaded. Add a removal function which clears the irq handler and removes the irq domain. With this cleanup in place, it's possible to unload and reload the module. Signed-off-by: Martin Kaiser Reviewed-by: Lucas Stach Signed-off-by: Lee Jones --- drivers/mfd/fsl-imx25-tsadc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index 14189efd70d0..dbb85caaafed 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -179,6 +179,19 @@ static int mx25_tsadc_probe(struct platform_device *pdev) return devm_of_platform_populate(dev); } +static int mx25_tsadc_remove(struct platform_device *pdev) +{ + struct mx25_tsadc *tsadc = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + if (irq) { + irq_set_chained_handler_and_data(irq, NULL, NULL); + irq_domain_remove(tsadc->domain); + } + + return 0; +} + static const struct of_device_id mx25_tsadc_ids[] = { { .compatible = "fsl,imx25-tsadc" }, { /* Sentinel */ } @@ -191,6 +204,7 @@ static struct platform_driver mx25_tsadc_driver = { .of_match_table = of_match_ptr(mx25_tsadc_ids), }, .probe = mx25_tsadc_probe, + .remove = mx25_tsadc_remove, }; module_platform_driver(mx25_tsadc_driver); -- cgit v1.2.3 From f38aa351d0c73280ac0f3a0cef52e3dc298bb73c Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Wed, 25 Oct 2017 16:15:01 +0200 Subject: mfd: ssbi: Use devm_of_platform_populate() Use devm_of_platform_populate() instead of of_platform_populate() to be sure that of_platform_depopulate() is called when removing the driver. Signed-off-by: Benjamin Gaignard Signed-off-by: Lee Jones --- drivers/mfd/ssbi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/ssbi.c b/drivers/mfd/ssbi.c index 27986f641f7d..36b96fee4ce6 100644 --- a/drivers/mfd/ssbi.c +++ b/drivers/mfd/ssbi.c @@ -314,7 +314,7 @@ static int ssbi_probe(struct platform_device *pdev) spin_lock_init(&ssbi->lock); - return of_platform_populate(np, NULL, NULL, &pdev->dev); + return devm_of_platform_populate(&pdev->dev); } static const struct of_device_id ssbi_match_table[] = { -- cgit v1.2.3 From 9f17ceaa01133e9a67fd796617446e9499570e3d Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Wed, 1 Nov 2017 10:32:07 +0800 Subject: dt-bindings: mfd: Add Spreadtrum SC27xx PMIC documentation This patch adds the binding documentation for Spreadtrum SC27xx series PMIC device. Signed-off-by: Baolin Wang Acked-by: Rob Herring Acked-by: Lee Jones Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/sprd,sc27xx-pmic.txt | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt diff --git a/Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt b/Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt new file mode 100644 index 000000000000..21b9a897fca5 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt @@ -0,0 +1,40 @@ +Spreadtrum SC27xx Power Management Integrated Circuit (PMIC) + +The Spreadtrum SC27xx series PMICs contain SC2720, SC2721, SC2723, SC2730 +and SC2731. The Spreadtrum PMIC belonging to SC27xx series integrates all +mobile handset power management, audio codec, battery management and user +interface support function in a single chip. It has 6 major functional +blocks: +- DCDCs to support CPU, memory. +- LDOs to support both internal and external requirement. +- Battery management system, such as charger, fuel gauge. +- Audio codec. +- User interface function, such as indicator, flash LED and so on. +- IC level interface, such as power on/off control, RTC and typec and so on. + +Required properties: +- compatible: Should be one of the following: + "sprd,sc2720" + "sprd,sc2721" + "sprd,sc2723" + "sprd,sc2730" + "sprd,sc2731" +- reg: The address of the device chip select, should be 0. +- spi-max-frequency: Typically set to 26000000. +- interrupts: The interrupt line the device is connected to. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: The number of cells to describe an PMIC IRQ, must be 2. +- #address-cells: Child device offset number of cells, must be 1. +- #size-cells: Child device size number of cells, must be 0. + +Example: +pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; +}; -- cgit v1.2.3 From 25ca4ae43466a47c563b5b82d49c72f5cc918de8 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Wed, 1 Nov 2017 10:32:08 +0800 Subject: mfd: Add Spreadtrum SC27xx series PMICs driver This patch adds support for Spreadtrum SC27xx series PMIC MFD core, and It provides communication through the SPI interfaces. The SC27xx series PMICs contains the following 6 major components: - DCDCs - LDOs - Battery management system - Audio codec - User interface function, such as indicator, flash LED - IC level function, such as power on/off, type-c Signed-off-by: Baolin Wang Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 16 +++ drivers/mfd/Makefile | 1 + drivers/mfd/sprd-sc27xx-spi.c | 259 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+) create mode 100644 drivers/mfd/sprd-sc27xx-spi.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 5fecee6d972c..2382bfa3d839 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1070,6 +1070,22 @@ config MFD_SMSC To compile this driver as a module, choose M here: the module will be called smsc. +config MFD_SC27XX_PMIC + tristate "Spreadtrum SC27xx PMICs" + depends on ARCH_SPRD || COMPILE_TEST + depends on SPI_MASTER + select MFD_CORE + select REGMAP_SPI + select REGMAP_IRQ + help + This enables support for the Spreadtrum SC27xx PMICs with SPI + interface. The SC27xx series PMICs integrate power management, + audio codec, battery management and user interface support + function (such as RTC, Typec, indicator and so on) in a single chip. + + This driver provides common support for accessing the SC27xx PMICs, + and it also adds the irq_chip parts for handling the PMIC chip events. + config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5d26f4064588..c5feaaef90ba 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -227,3 +227,4 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o +obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c new file mode 100644 index 000000000000..56a4782f0569 --- /dev/null +++ b/drivers/mfd/sprd-sc27xx-spi.c @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2017 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SPRD_PMIC_INT_MASK_STATUS 0x0 +#define SPRD_PMIC_INT_RAW_STATUS 0x4 +#define SPRD_PMIC_INT_EN 0x8 + +#define SPRD_SC2731_IRQ_BASE 0x140 +#define SPRD_SC2731_IRQ_NUMS 16 + +struct sprd_pmic { + struct regmap *regmap; + struct device *dev; + struct regmap_irq *irqs; + struct regmap_irq_chip irq_chip; + struct regmap_irq_chip_data *irq_data; + int irq; +}; + +struct sprd_pmic_data { + u32 irq_base; + u32 num_irqs; +}; + +/* + * Since different PMICs of SC27xx series can have different interrupt + * base address and irq number, we should save irq number and irq base + * in the device data structure. + */ +static const struct sprd_pmic_data sc2731_data = { + .irq_base = SPRD_SC2731_IRQ_BASE, + .num_irqs = SPRD_SC2731_IRQ_NUMS, +}; + +static const struct mfd_cell sprd_pmic_devs[] = { + { + .name = "sc27xx-wdt", + .of_compatible = "sprd,sc27xx-wdt", + }, { + .name = "sc27xx-rtc", + .of_compatible = "sprd,sc27xx-rtc", + }, { + .name = "sc27xx-charger", + .of_compatible = "sprd,sc27xx-charger", + }, { + .name = "sc27xx-chg-timer", + .of_compatible = "sprd,sc27xx-chg-timer", + }, { + .name = "sc27xx-fast-chg", + .of_compatible = "sprd,sc27xx-fast-chg", + }, { + .name = "sc27xx-chg-wdt", + .of_compatible = "sprd,sc27xx-chg-wdt", + }, { + .name = "sc27xx-typec", + .of_compatible = "sprd,sc27xx-typec", + }, { + .name = "sc27xx-flash", + .of_compatible = "sprd,sc27xx-flash", + }, { + .name = "sc27xx-eic", + .of_compatible = "sprd,sc27xx-eic", + }, { + .name = "sc27xx-efuse", + .of_compatible = "sprd,sc27xx-efuse", + }, { + .name = "sc27xx-thermal", + .of_compatible = "sprd,sc27xx-thermal", + }, { + .name = "sc27xx-adc", + .of_compatible = "sprd,sc27xx-adc", + }, { + .name = "sc27xx-audio-codec", + .of_compatible = "sprd,sc27xx-audio-codec", + }, { + .name = "sc27xx-regulator", + .of_compatible = "sprd,sc27xx-regulator", + }, { + .name = "sc27xx-vibrator", + .of_compatible = "sprd,sc27xx-vibrator", + }, { + .name = "sc27xx-keypad-led", + .of_compatible = "sprd,sc27xx-keypad-led", + }, { + .name = "sc27xx-bltc", + .of_compatible = "sprd,sc27xx-bltc", + }, { + .name = "sc27xx-fgu", + .of_compatible = "sprd,sc27xx-fgu", + }, { + .name = "sc27xx-7sreset", + .of_compatible = "sprd,sc27xx-7sreset", + }, { + .name = "sc27xx-poweroff", + .of_compatible = "sprd,sc27xx-poweroff", + }, +}; + +static int sprd_pmic_spi_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + + return spi_write(spi, data, count); +} + +static int sprd_pmic_spi_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + u32 rx_buf[2] = { 0 }; + int ret; + + /* Now we only support one PMIC register to read every time. */ + if (reg_size != sizeof(u32) || val_size != sizeof(u32)) + return -EINVAL; + + /* Copy address to read from into first element of SPI buffer. */ + memcpy(rx_buf, reg, sizeof(u32)); + ret = spi_read(spi, rx_buf, 1); + if (ret < 0) + return ret; + + memcpy(val, rx_buf, val_size); + return 0; +} + +static struct regmap_bus sprd_pmic_regmap = { + .write = sprd_pmic_spi_write, + .read = sprd_pmic_spi_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static const struct regmap_config sprd_pmic_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0xffff, +}; + +static int sprd_pmic_probe(struct spi_device *spi) +{ + struct sprd_pmic *ddata; + const struct sprd_pmic_data *pdata; + int ret, i; + + pdata = of_device_get_match_data(&spi->dev); + if (!pdata) { + dev_err(&spi->dev, "No matching driver data found\n"); + return -EINVAL; + } + + ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + ddata->regmap = devm_regmap_init(&spi->dev, &sprd_pmic_regmap, + &spi->dev, &sprd_pmic_config); + if (IS_ERR(ddata->regmap)) { + ret = PTR_ERR(ddata->regmap); + dev_err(&spi->dev, "Failed to allocate register map %d\n", ret); + return ret; + } + + spi_set_drvdata(spi, ddata); + ddata->dev = &spi->dev; + ddata->irq = spi->irq; + + ddata->irq_chip.name = dev_name(&spi->dev); + ddata->irq_chip.status_base = + pdata->irq_base + SPRD_PMIC_INT_MASK_STATUS; + ddata->irq_chip.mask_base = pdata->irq_base + SPRD_PMIC_INT_EN; + ddata->irq_chip.ack_base = 0; + ddata->irq_chip.num_regs = 1; + ddata->irq_chip.num_irqs = pdata->num_irqs; + ddata->irq_chip.mask_invert = true; + + ddata->irqs = devm_kzalloc(&spi->dev, sizeof(struct regmap_irq) * + pdata->num_irqs, GFP_KERNEL); + if (!ddata->irqs) + return -ENOMEM; + + ddata->irq_chip.irqs = ddata->irqs; + for (i = 0; i < pdata->num_irqs; i++) { + ddata->irqs[i].reg_offset = i / pdata->num_irqs; + ddata->irqs[i].mask = BIT(i % pdata->num_irqs); + } + + ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq, + IRQF_ONESHOT | IRQF_NO_SUSPEND, 0, + &ddata->irq_chip, &ddata->irq_data); + if (ret) { + dev_err(&spi->dev, "Failed to add PMIC irq chip %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(&spi->dev, PLATFORM_DEVID_AUTO, + sprd_pmic_devs, ARRAY_SIZE(sprd_pmic_devs), + NULL, 0, + regmap_irq_get_domain(ddata->irq_data)); + if (ret) { + dev_err(&spi->dev, "Failed to register device %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id sprd_pmic_match[] = { + { .compatible = "sprd,sc2731", .data = &sc2731_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, sprd_pmic_match); + +static struct spi_driver sprd_pmic_driver = { + .driver = { + .name = "sc27xx-pmic", + .bus = &spi_bus_type, + .of_match_table = sprd_pmic_match, + }, + .probe = sprd_pmic_probe, +}; + +static int __init sprd_pmic_init(void) +{ + return spi_register_driver(&sprd_pmic_driver); +} +subsys_initcall(sprd_pmic_init); + +static void __exit sprd_pmic_exit(void) +{ + spi_unregister_driver(&sprd_pmic_driver); +} +module_exit(sprd_pmic_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Spreadtrum SC27xx PMICs driver"); +MODULE_AUTHOR("Baolin Wang "); -- cgit v1.2.3 From 9a43206bffe83459d9a609105aa4c379a9b6f6d4 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 18 Oct 2017 16:31:31 +0800 Subject: mfd: axp20x: Add axp20x-regulator cell for AXP813 Now that axp20x-regulator supports AXP813, we can add a cell for it to enable it. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Tested-by: Maxime Ripard Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 336de66ca408..2468b431bb22 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -876,6 +876,8 @@ static struct mfd_cell axp813_cells[] = { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), .resources = axp803_pek_resources, + }, { + .name = "axp20x-regulator", } }; -- cgit v1.2.3 From b2596d70351370530d3fce16f3b6e6f1cd4dbdf0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 Sep 2017 12:51:51 -0300 Subject: dt-bindings: mfd: mc13xxx: Remove obsolete property The 'fsl,spi-num-chipselects' property is obsolete according to Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt, so remove it from the example. Signed-off-by: Fabio Estevam Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/mc13xxx.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt index 39ba4146769d..ac235fe385fc 100644 --- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -113,7 +113,6 @@ MC13892 regulators: Examples: ecspi@70010000 { /* ECSPI1 */ - fsl,spi-num-chipselects = <2>; cs-gpios = <&gpio4 24 0>, /* GPIO4_24 */ <&gpio4 25 0>; /* GPIO4_25 */ -- cgit v1.2.3