From 4533d8551b7dc594f5d203c1dc6c1527a21ad61d Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 5 Jun 2017 12:08:01 -0700 Subject: mfd: intel_soc_pmic_bxtwc: Fix TMU interrupt index TMU interrupts are registered as a separate interrupt chip, and hence it should start its interrupt index(BXTWC_TMU_IRQ) number from 0. But currently, BXTWC_TMU_IRQ is defined as part of enum bxtwc_irqs_level2 and its index value is 11. Since this index value is used when calculating .num_irqs of regmap_irq_chip_tmu, it incorrectly reports number of IRQs as 12 instead of actual value of 1. This patch fixes this issue by creating new enum of tmu IRQs and resetting its starting index to 0. Signed-off-by: Kuppuswamy Sathyanarayanan Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_bxtwc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 8c3cbf63c6ad..7cbaf1eda3f8 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -95,7 +95,10 @@ enum bxtwc_irqs_level2 { BXTWC_GPIO0_IRQ, BXTWC_GPIO1_IRQ, BXTWC_CRIT_IRQ, - BXTWC_TMU_IRQ, +}; + +enum bxtwc_irqs_tmu { + BXTWC_TMU_IRQ = 0, }; static const struct regmap_irq bxtwc_regmap_irqs[] = { -- cgit v1.2.3 From c4949630fe437bc15346abbd1a92dee8e80a85d4 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 5 Jun 2017 12:08:02 -0700 Subject: mfd: intel_soc_pmic_bxtwc: Remove thermal second level IRQs Since all second level thermal IRQs are consumed by the same device(bxt_wcove_thermal), there is no need to expose them as separate interrupts. We can just export only the first level IRQs for thermal and let the device(bxt_wcove_thermal) driver handle the second level IRQs based on thermal interrupt status register. Also, just using only the first level IRQ will eliminate the bug involved in requesting only the second level IRQ and not explicitly enable the first level IRQ. For more info on this issue please read the details at, https://lkml.org/lkml/2017/2/27/148 This patch also makes relevant change in bxt_wcove_thermal driver to use only first level PMIC thermal IRQ. Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Zhang Rui Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_bxtwc.c | 32 ++++++++++++-------------------- drivers/thermal/intel_bxt_pmic_thermal.c | 2 +- 2 files changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 7cbaf1eda3f8..7c1ed27c7720 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -84,10 +84,7 @@ enum bxtwc_irqs { enum bxtwc_irqs_level2 { /* Level 2 */ - BXTWC_THRM0_IRQ = 0, - BXTWC_THRM1_IRQ, - BXTWC_THRM2_IRQ, - BXTWC_BCU_IRQ, + BXTWC_BCU_IRQ = 0, BXTWC_ADC_IRQ, BXTWC_USBC_IRQ, BXTWC_CHGR0_IRQ, @@ -114,17 +111,14 @@ static const struct regmap_irq bxtwc_regmap_irqs[] = { }; static const struct regmap_irq bxtwc_regmap_irqs_level2[] = { - REGMAP_IRQ_REG(BXTWC_THRM0_IRQ, 0, 0xff), - REGMAP_IRQ_REG(BXTWC_THRM1_IRQ, 1, 0xbf), - REGMAP_IRQ_REG(BXTWC_THRM2_IRQ, 2, 0xff), - REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 3, 0x1f), - REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 4, 0xff), - REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 5, BIT(5)), - REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x1f), - REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 6, 0x1f), - REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 7, 0xff), - REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 8, 0x3f), - REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03), + REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f), + REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 1, 0xff), + REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 2, BIT(5)), + REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 2, 0x1f), + REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 3, 0x1f), + REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 4, 0xff), + REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 5, 0x3f), + REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 6, 0x03), }; static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { @@ -142,8 +136,8 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip = { static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = { .name = "bxtwc_irq_chip_level2", - .status_base = BXTWC_THRM0IRQ, - .mask_base = BXTWC_MTHRM0IRQ, + .status_base = BXTWC_BCUIRQ, + .mask_base = BXTWC_MBCUIRQ, .irqs = bxtwc_regmap_irqs_level2, .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_level2), .num_regs = 10, @@ -177,9 +171,7 @@ static struct resource charger_resources[] = { }; static struct resource thermal_resources[] = { - DEFINE_RES_IRQ(BXTWC_THRM0_IRQ), - DEFINE_RES_IRQ(BXTWC_THRM1_IRQ), - DEFINE_RES_IRQ(BXTWC_THRM2_IRQ), + DEFINE_RES_IRQ(BXTWC_THRM_LVL1_IRQ), }; static struct resource bcu_resources[] = { diff --git a/drivers/thermal/intel_bxt_pmic_thermal.c b/drivers/thermal/intel_bxt_pmic_thermal.c index 0f19a393ddd8..ef6b32242ccb 100644 --- a/drivers/thermal/intel_bxt_pmic_thermal.c +++ b/drivers/thermal/intel_bxt_pmic_thermal.c @@ -241,7 +241,7 @@ static int pmic_thermal_probe(struct platform_device *pdev) } regmap = pmic->regmap; - regmap_irq_chip = pmic->irq_chip_data_level2; + regmap_irq_chip = pmic->irq_chip_data; pmic_irq_count = 0; while ((irq = platform_get_irq(pdev, pmic_irq_count)) != -ENXIO) { -- cgit v1.2.3 From a1d28c5991137f789162f412764dd7471aca6ec0 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 5 Jun 2017 12:08:03 -0700 Subject: mfd: intel_soc_pmic_bxtwc: Remove second level IRQ for gpio device Currently all PMIC GPIO domain IRQs are consumed by the same device(bxt_wcove_gpio), so there is no need to export them as separate interrupts. We can just export only the first level GPIO IRQ(BXTWC_GPIO_LVL1_IRQ) as an IRQ resource and let the GPIO device driver(bxt_wcove_gpio) handle the GPIO sub domain IRQs based on status value of GPIO level2 interrupt status register. Also, just using only the first level IRQ will eliminate the bug involved in requesting only the second level IRQ and not explicitly enable the first level IRQ. For more info on this issue please read the details at, https://lkml.org/lkml/2017/2/27/148 This patch also makes relevant change in Whiskey cove GPIO driver to use only first level PMIC GPIO IRQ. Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Linus Walleij Acked-for-MFD-by: Lee Jones Signed-off-by: Lee Jones --- drivers/gpio/gpio-wcove.c | 14 +++++++++++++- drivers/mfd/intel_soc_pmic_bxtwc.c | 7 +------ 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 7b1bc20be209..bba7704e1654 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -401,7 +401,7 @@ static int wcove_gpio_probe(struct platform_device *pdev) if (!wg) return -ENOMEM; - wg->regmap_irq_chip = pmic->irq_chip_data_level2; + wg->regmap_irq_chip = pmic->irq_chip_data; platform_set_drvdata(pdev, wg); @@ -449,6 +449,18 @@ static int wcove_gpio_probe(struct platform_device *pdev) gpiochip_set_nested_irqchip(&wg->chip, &wcove_irqchip, virq); + /* Enable GPIO0 interrupts */ + ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE, GPIO_IRQ0_MASK, + 0x00); + if (ret) + return ret; + + /* Enable GPIO1 interrupts */ + ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE + 1, GPIO_IRQ1_MASK, + 0x00); + if (ret) + return ret; + return 0; } diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 7c1ed27c7720..af11c43c27d2 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -89,8 +89,6 @@ enum bxtwc_irqs_level2 { BXTWC_USBC_IRQ, BXTWC_CHGR0_IRQ, BXTWC_CHGR1_IRQ, - BXTWC_GPIO0_IRQ, - BXTWC_GPIO1_IRQ, BXTWC_CRIT_IRQ, }; @@ -116,8 +114,6 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = { REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 2, BIT(5)), REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 2, 0x1f), REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 3, 0x1f), - REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 4, 0xff), - REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 5, 0x3f), REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 6, 0x03), }; @@ -153,8 +149,7 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { }; static struct resource gpio_resources[] = { - DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"), - DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"), + DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"), }; static struct resource adc_resources[] = { -- cgit v1.2.3 From 5131f072e5bff3a6a1da6b8f4882b6747e8c2a49 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 5 Jun 2017 12:08:04 -0700 Subject: mfd: intel_soc_pmic_bxtwc: Utilize devm_* functions in driver probe Cleanup the resource allocation/free code in probe function by using devm_* calls. Signed-off-by: Kuppuswamy Sathyanarayanan Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_bxtwc.c | 54 +++++++++++++------------------------- 1 file changed, 18 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index af11c43c27d2..feeda6ed546c 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -399,45 +399,44 @@ static int bxtwc_probe(struct platform_device *pdev) return ret; } - ret = regmap_add_irq_chip(pmic->regmap, pmic->irq, - IRQF_ONESHOT | IRQF_SHARED, - 0, &bxtwc_regmap_irq_chip, - &pmic->irq_chip_data); + ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, + IRQF_ONESHOT | IRQF_SHARED, + 0, &bxtwc_regmap_irq_chip, + &pmic->irq_chip_data); if (ret) { dev_err(&pdev->dev, "Failed to add IRQ chip\n"); return ret; } - ret = regmap_add_irq_chip(pmic->regmap, pmic->irq, - IRQF_ONESHOT | IRQF_SHARED, - 0, &bxtwc_regmap_irq_chip_level2, - &pmic->irq_chip_data_level2); + ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, + IRQF_ONESHOT | IRQF_SHARED, + 0, &bxtwc_regmap_irq_chip_level2, + &pmic->irq_chip_data_level2); if (ret) { dev_err(&pdev->dev, "Failed to add secondary IRQ chip\n"); - goto err_irq_chip_level2; + return ret; } - ret = regmap_add_irq_chip(pmic->regmap, pmic->irq, - IRQF_ONESHOT | IRQF_SHARED, - 0, &bxtwc_regmap_irq_chip_tmu, - &pmic->irq_chip_data_tmu); + ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, + IRQF_ONESHOT | IRQF_SHARED, + 0, &bxtwc_regmap_irq_chip_tmu, + &pmic->irq_chip_data_tmu); if (ret) { dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); - goto err_irq_chip_tmu; + return ret; } - ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, - ARRAY_SIZE(bxt_wc_dev), NULL, 0, - NULL); + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, + ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); if (ret) { dev_err(&pdev->dev, "Failed to add devices\n"); - goto err_mfd; + return ret; } ret = sysfs_create_group(&pdev->dev.kobj, &bxtwc_group); if (ret) { dev_err(&pdev->dev, "Failed to create sysfs group %d\n", ret); - goto err_sysfs; + return ret; } /* @@ -451,28 +450,11 @@ static int bxtwc_probe(struct platform_device *pdev) BXTWC_MIRQLVL1_MCHGR, 0); return 0; - -err_sysfs: - mfd_remove_devices(&pdev->dev); -err_mfd: - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu); -err_irq_chip_tmu: - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); -err_irq_chip_level2: - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); - - return ret; } static int bxtwc_remove(struct platform_device *pdev) { - struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev); - sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group); - mfd_remove_devices(&pdev->dev); - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu); return 0; } -- cgit v1.2.3 From 57129044f5044dcd73c22d91491906104bd331fd Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 5 Jun 2017 12:08:05 -0700 Subject: mfd: intel_soc_pmic_bxtwc: Use chained IRQs for second level IRQ chips Whishkey cove PMIC has support to mask/unmask interrupts at two levels. At first level we can mask/unmask interrupt domains like TMU, GPIO, ADC, CHGR, BCU THERMAL and PWRBTN and at second level, it provides facility to mask/unmask individual interrupts belong each of this domain. For example, in case of TMU, at first level we have TMU interrupt domain, and at second level we have two interrupts, wake alarm, system alarm that belong to the TMU interrupt domain. Currently, in this driver all first level IRQs are registered as part of IRQ chip(bxtwc_regmap_irq_chip). By default, after you register the IRQ chip from your driver, all IRQs in that chip will masked and can only be enabled if that IRQ is requested using request_irq() call. This is the default Linux IRQ behavior model. And whenever a dependent device that belongs to PMIC requests only the second level IRQ and not explicitly unmask the first level IRQ, then in essence the second level IRQ will still be disabled. For example, if TMU device driver request wake_alarm IRQ and not explicitly unmask TMU level 1 IRQ then according to the default Linux IRQ model, wake_alarm IRQ will still be disabled. So the proper solution to fix this issue is to use the chained IRQ chip concept. We should chain all the second level chip IRQs to the corresponding first level IRQ. To do this, we need to create separate IRQ chips for every group of second level IRQs. In case of TMU, when adding second level IRQ chip, instead of using PMIC IRQ we should use the corresponding first level IRQ. So the following code will change from ret = regmap_add_irq_chip(pmic->regmap, pmic->irq, ...) to, virq = regmap_irq_get_virq(&pmic->irq_chip_data, BXTWC_TMU_LVL1_IRQ); ret = regmap_add_irq_chip(pmic->regmap, virq, ...) In case of Whiskey Cove Type-C driver, Since USBC IRQ is moved under charger level2 IRQ chip. We should use charger IRQ chip(irq_chip_data_chgr) to get the USBC virtual IRQ number. Signed-off-by: Kuppuswamy Sathyanarayanan Reviewed-by: Andy Shevchenko Revieved-by: Heikki Krogerus Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_bxtwc.c | 168 ++++++++++++++++++++++++++++++------- drivers/usb/typec/typec_wcove.c | 2 +- include/linux/mfd/intel_soc_pmic.h | 5 +- 3 files changed, 143 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index feeda6ed546c..15bc052704a6 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -82,20 +82,28 @@ enum bxtwc_irqs { BXTWC_PWRBTN_IRQ, }; -enum bxtwc_irqs_level2 { - /* Level 2 */ +enum bxtwc_irqs_bcu { BXTWC_BCU_IRQ = 0, - BXTWC_ADC_IRQ, - BXTWC_USBC_IRQ, +}; + +enum bxtwc_irqs_adc { + BXTWC_ADC_IRQ = 0, +}; + +enum bxtwc_irqs_chgr { + BXTWC_USBC_IRQ = 0, BXTWC_CHGR0_IRQ, BXTWC_CHGR1_IRQ, - BXTWC_CRIT_IRQ, }; enum bxtwc_irqs_tmu { BXTWC_TMU_IRQ = 0, }; +enum bxtwc_irqs_crit { + BXTWC_CRIT_IRQ = 0, +}; + static const struct regmap_irq bxtwc_regmap_irqs[] = { REGMAP_IRQ_REG(BXTWC_PWRBTN_LVL1_IRQ, 0, BIT(0)), REGMAP_IRQ_REG(BXTWC_TMU_LVL1_IRQ, 0, BIT(1)), @@ -108,19 +116,28 @@ static const struct regmap_irq bxtwc_regmap_irqs[] = { REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 1, 0x03), }; -static const struct regmap_irq bxtwc_regmap_irqs_level2[] = { +static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = { REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f), - REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 1, 0xff), - REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 2, BIT(5)), - REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 2, 0x1f), - REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 3, 0x1f), - REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 6, 0x03), +}; + +static const struct regmap_irq bxtwc_regmap_irqs_adc[] = { + REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, 0xff), +}; + +static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = { + REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, BIT(5)), + REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f), + REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f), }; static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06), }; +static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { + REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, 0x03), +}; + static struct regmap_irq_chip bxtwc_regmap_irq_chip = { .name = "bxtwc_irq_chip", .status_base = BXTWC_IRQLVL1, @@ -130,15 +147,6 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip = { .num_regs = 2, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = { - .name = "bxtwc_irq_chip_level2", - .status_base = BXTWC_BCUIRQ, - .mask_base = BXTWC_MBCUIRQ, - .irqs = bxtwc_regmap_irqs_level2, - .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_level2), - .num_regs = 10, -}; - static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { .name = "bxtwc_irq_chip_tmu", .status_base = BXTWC_TMUIRQ, @@ -148,6 +156,42 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { .num_regs = 1, }; +static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { + .name = "bxtwc_irq_chip_bcu", + .status_base = BXTWC_BCUIRQ, + .mask_base = BXTWC_MBCUIRQ, + .irqs = bxtwc_regmap_irqs_bcu, + .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_bcu), + .num_regs = 1, +}; + +static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { + .name = "bxtwc_irq_chip_adc", + .status_base = BXTWC_ADCIRQ, + .mask_base = BXTWC_MADCIRQ, + .irqs = bxtwc_regmap_irqs_adc, + .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_adc), + .num_regs = 1, +}; + +static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { + .name = "bxtwc_irq_chip_chgr", + .status_base = BXTWC_CHGR0IRQ, + .mask_base = BXTWC_MCHGR0IRQ, + .irqs = bxtwc_regmap_irqs_chgr, + .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_chgr), + .num_regs = 2, +}; + +static struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { + .name = "bxtwc_irq_chip_crit", + .status_base = BXTWC_CRITIRQ, + .mask_base = BXTWC_MCRITIRQ, + .irqs = bxtwc_regmap_irqs_crit, + .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_crit), + .num_regs = 1, +}; + static struct resource gpio_resources[] = { DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"), }; @@ -357,6 +401,26 @@ static const struct regmap_config bxtwc_regmap_config = { .reg_read = regmap_ipc_byte_reg_read, }; +static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, + struct regmap_irq_chip_data *pdata, + int pirq, int irq_flags, + const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data) +{ + int irq; + + irq = regmap_irq_get_virq(pdata, pirq); + if (irq < 0) { + dev_err(pmic->dev, + "Failed to get parent vIRQ(%d) for chip %s, ret:%d\n", + pirq, chip->name, irq); + return irq; + } + + return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags, + 0, chip, data); +} + static int bxtwc_probe(struct platform_device *pdev) { int ret; @@ -408,21 +472,65 @@ static int bxtwc_probe(struct platform_device *pdev) return ret; } - ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, - IRQF_ONESHOT | IRQF_SHARED, - 0, &bxtwc_regmap_irq_chip_level2, - &pmic->irq_chip_data_level2); + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, + BXTWC_TMU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_tmu, + &pmic->irq_chip_data_tmu); if (ret) { - dev_err(&pdev->dev, "Failed to add secondary IRQ chip\n"); + dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); return ret; } - ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, - IRQF_ONESHOT | IRQF_SHARED, - 0, &bxtwc_regmap_irq_chip_tmu, - &pmic->irq_chip_data_tmu); + /* Add chained IRQ handler for BCU IRQs */ + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, + BXTWC_BCU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_bcu, + &pmic->irq_chip_data_bcu); + + if (ret) { - dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); + dev_err(&pdev->dev, "Failed to add BUC IRQ chip\n"); + return ret; + } + + /* Add chained IRQ handler for ADC IRQs */ + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, + BXTWC_ADC_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_adc, + &pmic->irq_chip_data_adc); + + + if (ret) { + dev_err(&pdev->dev, "Failed to add ADC IRQ chip\n"); + return ret; + } + + /* Add chained IRQ handler for CHGR IRQs */ + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, + BXTWC_CHGR_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_chgr, + &pmic->irq_chip_data_chgr); + + + if (ret) { + dev_err(&pdev->dev, "Failed to add CHGR IRQ chip\n"); + return ret; + } + + /* Add chained IRQ handler for CRIT IRQs */ + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, + BXTWC_CRIT_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_crit, + &pmic->irq_chip_data_crit); + + + if (ret) { + dev_err(&pdev->dev, "Failed to add CRIT IRQ chip\n"); return ret; } diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/typec_wcove.c index d5a7b21fa3f1..00a4bd20fb60 100644 --- a/drivers/usb/typec/typec_wcove.c +++ b/drivers/usb/typec/typec_wcove.c @@ -303,7 +303,7 @@ static int wcove_typec_probe(struct platform_device *pdev) wcove->dev = &pdev->dev; wcove->regmap = pmic->regmap; - ret = regmap_irq_get_virq(pmic->irq_chip_data_level2, + ret = regmap_irq_get_virq(pmic->irq_chip_data_chgr, platform_get_irq(pdev, 0)); if (ret < 0) return ret; diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h index 956caa0628f5..5aacdb017a9f 100644 --- a/include/linux/mfd/intel_soc_pmic.h +++ b/include/linux/mfd/intel_soc_pmic.h @@ -25,8 +25,11 @@ struct intel_soc_pmic { int irq; struct regmap *regmap; struct regmap_irq_chip_data *irq_chip_data; - struct regmap_irq_chip_data *irq_chip_data_level2; struct regmap_irq_chip_data *irq_chip_data_tmu; + struct regmap_irq_chip_data *irq_chip_data_bcu; + struct regmap_irq_chip_data *irq_chip_data_adc; + struct regmap_irq_chip_data *irq_chip_data_chgr; + struct regmap_irq_chip_data *irq_chip_data_crit; struct device *dev; }; -- cgit v1.2.3 From 94d68594a7b4fd2eec457f22110de644e1c4ee57 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 5 Jun 2017 12:08:06 -0700 Subject: platform/x86: intel_bxtwc_tmu: Remove first level IRQ unmask Currently in WCOVE PMIC MFD driver, all second level IRQ chips are chained to the respective first level IRQs. So there is no need for explicitly unmasking the first level IRQ in this driver. This patches removes this level 1 IRQ unmask support. Signed-off-by: Kuppuswamy Sathyanarayanan Reviewed-by: Darren Hart (VMware) Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/platform/x86/intel_bxtwc_tmu.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c index e202abd5b0df..ea865d4ca220 100644 --- a/drivers/platform/x86/intel_bxtwc_tmu.c +++ b/drivers/platform/x86/intel_bxtwc_tmu.c @@ -92,10 +92,6 @@ static int bxt_wcove_tmu_probe(struct platform_device *pdev) } wctmu->irq = virq; - /* Enable TMU interrupts */ - regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1, - BXTWC_MIRQLVL1_MTMU, 0); - /* Unmask TMU second level Wake & System alarm */ regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG, BXTWC_TMU_ALRM_MASK, 0); -- cgit v1.2.3 From b418bbff36dd25dc49ed6abbb1e1deedd0d7cff5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 May 2017 11:23:14 +0300 Subject: mfd: intel-lpss: Add Intel Cannonlake PCI IDs Intel Cannonlake PCH has the same LPSS than Intel Kabylake. Add the new IDs to the list of supported devices. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss-pci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 16ffeaeb1385..ad388bb056cd 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -201,6 +201,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, + /* CNL-LP */ + { PCI_VDEVICE(INTEL, 0x9da8), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9da9), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9de8), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&spt_i2c_info }, /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, @@ -219,6 +232,17 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&spt_uart_info }, + /* CNL-H */ + { PCI_VDEVICE(INTEL, 0xa328), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa329), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&spt_i2c_info }, { } }; MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids); -- cgit v1.2.3 From 6ae0cc90d9e7c026d0a342403f0cd559f743edab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 15 May 2017 11:44:05 +0200 Subject: mfd: ipaq-micro: Dump debugging hexdumps These hexdumps get printed no matter if CONFIG_DEBUG is set or not. Just get rid of them. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ipaq-micro.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index 124aad2b1d02..cd762d08f116 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -53,8 +53,6 @@ static void ipaq_micro_trigger_tx(struct ipaq_micro *micro) tx->buf[bp++] = checksum; tx->len = bp; tx->index = 0; - print_hex_dump_debug("data: ", DUMP_PREFIX_OFFSET, 16, 1, - tx->buf, tx->len, true); /* Enable interrupt */ val = readl(micro->base + UTCR3); @@ -281,9 +279,6 @@ static void __init ipaq_micro_eeprom_dump(struct ipaq_micro *micro) dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92)); dev_info(micro->dev, "screen: %u x %u\n", ipaq_micro_to_u16(dump+94), ipaq_micro_to_u16(dump+96)); - print_hex_dump_debug("eeprom: ", DUMP_PREFIX_OFFSET, 16, 1, - dump, 256, true); - } static void micro_tx_chars(struct ipaq_micro *micro) -- cgit v1.2.3 From dcb0574b4b15e197e4ab2b503efcfa5eb172083d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 15 May 2017 13:51:24 +0100 Subject: mfd: wm831x: Remove redundant !pdata checks Since a copy of the pdata was added into the core struct in commit f6dd8449cd50 ("mfd: wm831x: Add basic device tree binding") the pdata pointer in probe can no longer be NULL. As such remove the redundant checks for this case. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm831x-core.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 13a4c1190dca..e70d35ef5c6d 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1766,7 +1766,7 @@ int wm831x_device_init(struct wm831x *wm831x, int irq) } wm831x->locked = 1; - if (pdata && pdata->pre_init) { + if (pdata->pre_init) { ret = pdata->pre_init(wm831x); if (ret != 0) { dev_err(wm831x->dev, "pre_init() failed: %d\n", ret); @@ -1774,19 +1774,17 @@ int wm831x_device_init(struct wm831x *wm831x, int irq) } } - if (pdata) { - for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { - if (!pdata->gpio_defaults[i]) - continue; + for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { + if (!pdata->gpio_defaults[i]) + continue; - wm831x_reg_write(wm831x, - WM831X_GPIO1_CONTROL + i, - pdata->gpio_defaults[i] & 0xffff); - } + wm831x_reg_write(wm831x, + WM831X_GPIO1_CONTROL + i, + pdata->gpio_defaults[i] & 0xffff); } /* Multiply by 10 as we have many subdevices of the same type */ - if (pdata && pdata->wm831x_num) + if (pdata->wm831x_num) wm831x_num = pdata->wm831x_num * 10; else wm831x_num = -1; @@ -1809,7 +1807,7 @@ int wm831x_device_init(struct wm831x *wm831x, int irq) ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8311_devs, ARRAY_SIZE(wm8311_devs), NULL, 0, NULL); - if (!pdata || !pdata->disable_touch) + if (!pdata->disable_touch) mfd_add_devices(wm831x->dev, wm831x_num, touch_devs, ARRAY_SIZE(touch_devs), NULL, 0, NULL); @@ -1819,7 +1817,7 @@ int wm831x_device_init(struct wm831x *wm831x, int irq) ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8312_devs, ARRAY_SIZE(wm8312_devs), NULL, 0, NULL); - if (!pdata || !pdata->disable_touch) + if (!pdata->disable_touch) mfd_add_devices(wm831x->dev, wm831x_num, touch_devs, ARRAY_SIZE(touch_devs), NULL, 0, NULL); @@ -1865,7 +1863,7 @@ int wm831x_device_init(struct wm831x *wm831x, int irq) dev_info(wm831x->dev, "32.768kHz clock disabled, no RTC\n"); } - if (pdata && pdata->backlight) { + if (pdata->backlight) { /* Treat errors as non-critical */ ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, ARRAY_SIZE(backlight_devs), NULL, @@ -1877,7 +1875,7 @@ int wm831x_device_init(struct wm831x *wm831x, int irq) wm831x_otp_init(wm831x); - if (pdata && pdata->post_init) { + if (pdata->post_init) { ret = pdata->post_init(wm831x); if (ret != 0) { dev_err(wm831x->dev, "post_init() failed: %d\n", ret); -- cgit v1.2.3 From ecca790a1aabd4a0e6fcdf7c3a0c81f3a4f38b6a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 15 May 2017 23:24:11 -0700 Subject: mfd: rn5t618: Unregister restart handler on remove Remove the restart handler registered in probe on device remove. Fixes: a370f60a58ec ("mfd: rn5t618: Register restart handler") Signed-off-by: Stefan Agner Signed-off-by: Lee Jones --- drivers/mfd/rn5t618.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 8131d1975745..f4037d42a60f 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -155,6 +155,8 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c) pm_power_off = NULL; } + unregister_restart_handler(&rn5t618_restart_handler); + return 0; } -- cgit v1.2.3 From 9b79ff104f73de63efc958cc0dec3c826aee3ffd Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 18 May 2017 15:16:50 +0800 Subject: mfd: axp20x: Add axp20x-regulator cell for AXP803 As axp20x-regulator now supports AXP803, add a cell for it. Signed-off-by: Icenowy Zheng Acked-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 1dc6235778eb..917b6ddc4f15 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -848,7 +848,8 @@ static struct mfd_cell axp803_cells[] = { .name = "axp20x-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), .resources = axp803_pek_resources, - } + }, + { .name = "axp20x-regulator" }, }; static struct mfd_cell axp806_cells[] = { -- cgit v1.2.3 From 87d284443d071dc70344dda4b2fb43723686acdb Mon Sep 17 00:00:00 2001 From: Steven Feng Date: Tue, 23 May 2017 15:13:24 +0800 Subject: mfd: rtsx: Do retry when DMA transfer error The request should be resent when DMA transfer error occurred. For rts5227, the clock rate needs to be reduced when error occurred. Signed-off-by: Steven Feng Signed-off-by: Lee Jones --- drivers/mfd/rtsx_pcr.c | 17 +++++++++++++++-- include/linux/mfd/rtsx_pci.h | 5 +++++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 850590aac008..a0ac89dfdf0f 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "rtsx_pcr.h" @@ -452,8 +453,12 @@ int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist, } spin_lock_irqsave(&pcr->lock, flags); - if (pcr->trans_result == TRANS_RESULT_FAIL) - err = -EINVAL; + if (pcr->trans_result == TRANS_RESULT_FAIL) { + err = -EILSEQ; + if (pcr->dma_error_count < RTS_MAX_TIMES_FREQ_REDUCTION) + pcr->dma_error_count++; + } + else if (pcr->trans_result == TRANS_NO_DEVICE) err = -ENODEV; spin_unlock_irqrestore(&pcr->lock, flags); @@ -659,6 +664,13 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, if (err < 0) return err; + /* Reduce card clock by 20MHz each time a DMA transfer error occurs */ + if (card_clock == UHS_SDR104_MAX_DTR && + pcr->dma_error_count && + PCI_PID(pcr) == RTS5227_DEVICE_ID) + card_clock = UHS_SDR104_MAX_DTR - + (pcr->dma_error_count * 20000000); + card_clock /= 1000000; pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock); @@ -894,6 +906,7 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) pcr->card_removed |= SD_EXIST; pcr->card_inserted &= ~SD_EXIST; } + pcr->dma_error_count = 0; } if (int_reg & MS_INT) { diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 7eb7cbac0a9a..116816fb9110 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -850,6 +850,9 @@ #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) +#define RTS5227_DEVICE_ID 0x5227 +#define RTS_MAX_TIMES_FREQ_REDUCTION 8 + struct rtsx_pcr; struct pcr_handle { @@ -957,6 +960,8 @@ struct rtsx_pcr { int num_slots; struct rtsx_slot *slots; + + u8 dma_error_count; }; #define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid)) -- cgit v1.2.3 From 800e54558b0f1444e480ad4eb8d4a774899875d8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 24 May 2017 04:26:23 -0500 Subject: mfd: wm831x-i2c: Add NULL check before pointer dereference Add NULL check before dereferencing pointer of_id in order to avoid a potential NULL pointer dereference. Addresses-Coverity-ID: 1408829 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Lee Jones --- drivers/mfd/wm831x-i2c.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index 781af060f32d..22f7054d1b28 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -37,6 +37,10 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, if (i2c->dev.of_node) { of_id = of_match_device(wm831x_of_match, &i2c->dev); + if (!of_id) { + dev_err(&i2c->dev, "Failed to match device\n"); + return -ENODEV; + } type = (enum wm831x_parent)of_id->data; } else { type = (enum wm831x_parent)id->driver_data; -- cgit v1.2.3 From 7b55033fbed07bad695ba744db3070c1cc351dc4 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 24 May 2017 04:18:52 -0500 Subject: mfd: wm831x-spi: Add NULL check before pointer dereference Add NULL check before dereferencing pointer of_id in order to avoid a potential NULL pointer dereference. Addresses-Coverity-ID: 1408830 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Lee Jones --- drivers/mfd/wm831x-spi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index c332e2885b26..018ce652ae57 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -34,6 +34,10 @@ static int wm831x_spi_probe(struct spi_device *spi) if (spi->dev.of_node) { of_id = of_match_device(wm831x_of_match, &spi->dev); + if (!of_id) { + dev_err(&spi->dev, "Failed to match device\n"); + return -ENODEV; + } type = (enum wm831x_parent)of_id->data; } else { type = (enum wm831x_parent)id->driver_data; -- cgit v1.2.3 From 485857390927ee359a47f1c528ed6ca5725ddbc9 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 25 May 2017 22:26:21 +0200 Subject: mfd: twl4030-irq: Log an error in twl4030_sih_setup if the module cannot be found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As silently failing isn't that nice, emit an error message at a place that was silent on failure up to now. Signed-off-by: Uwe Kleine-König Signed-off-by: Lee Jones --- drivers/mfd/twl4030-irq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index b46c0cfc27d9..378c02d43bf7 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -638,8 +638,10 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base) } } - if (status < 0) + if (status < 0) { + dev_err(dev, "module to setup SIH for not found\n"); return status; + } agent = kzalloc(sizeof(*agent), GFP_KERNEL); if (!agent) -- cgit v1.2.3 From 54698c2d0a5a4e8c19e98388019c2c0ae1b51745 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 24 May 2017 18:08:16 +0200 Subject: mfd: fsl-imx25-tsadc: Constify irq_domain_ops struct irq_domain_ops is not modified, so it can be made const. Signed-off-by: Tobias Klauser Signed-off-by: Lee Jones --- drivers/mfd/fsl-imx25-tsadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index ac430a396a89..190e375dc57a 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -59,7 +59,7 @@ static int mx25_tsadc_domain_map(struct irq_domain *d, unsigned int irq, return 0; } -static struct irq_domain_ops mx25_tsadc_domain_ops = { +static const struct irq_domain_ops mx25_tsadc_domain_ops = { .map = mx25_tsadc_domain_map, .xlate = irq_domain_xlate_onecell, }; -- cgit v1.2.3 From acebcff9eda8c38fd78acbfb9fab555b3a2ba5eb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 May 2017 13:15:30 +0200 Subject: mfd: intel_soc_pmic: Select designware i2c-bus driver The Crystal Cove PMIC provides an ACPI OPRegion handler, which must be available before other drivers using it are loaded, which is why INTEL_SOC_PMIC is a bool. Just having the driver is not enough, the driver for the i2c-bus must also be built in, to ensure this, this patch adds a select for it. This fixes errors like these during boot: mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166) ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299) ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543) ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543) acpi 80860F14:02: Failed to change power state to D0 While at it this patch also changes the human readable name of the Kconfig option to make clear the INTEL_SOC_PMIC option selects support for the Intel Crystal Cove PMIC and documents why this is a bool. [The above patch caused a build error on some archetectures] From: Arnd Bergmann I ran into a build error on ARM with a platform that has a non-standard clk implementation: drivers/clk/clk.o: In function `clk_disable': clk.c:(.text.clk_disable+0x0): multiple definition of `clk_disable' arch/arm/mach-omap1/clock.o:clock.c:(.text.clk_disable+0x0): first defined here drivers/clk/clk.o: In function `clk_enable': clk.c:(.text.clk_enable+0x0): multiple definition of `clk_enable' arch/arm/mach-omap1/clock.o:clock.c:(.text.clk_enable+0x0): first defined here The problem is a device driver that uses 'select COMMON_CLK', which is generally a bad idea: selecting a subsystem should only be done from a platform, otherwise we run into circular dependencies. The same driver also selects 'GPIOLIB' and 'I2C', which has a similar effect. This turns all three into 'depends on', as it should be. Finally, we can limit the build to x86, unless we are compile testing. First patch: Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Fix for first patch (squashed): Signed-off-by: Arnd Bergmann Signed-off-by: Hans de Goede Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3eb5c93595f6..2ca88fc4698d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -448,17 +448,22 @@ config LPC_SCH config INTEL_SOC_PMIC bool "Support for Crystal Cove PMIC" - depends on GPIOLIB - depends on I2C=y + depends on HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK + depends on X86 || COMPILE_TEST select MFD_CORE select REGMAP_I2C select REGMAP_IRQ + select I2C_DESIGNWARE_PLATFORM if ACPI help Select this option to enable support for Crystal Cove PMIC on some Intel SoC systems. The PMIC provides ADC, GPIO, thermal, charger and related power management functions on these systems. + This option is a bool as it provides an ACPI OpRegion which must be + 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_BXTWC tristate "Support for Intel Broxton Whiskey Cove PMIC" depends on INTEL_PMC_IPC -- cgit v1.2.3 From c42a8edbe95db8106a68d7680c8379c4f80d9845 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:53 +0200 Subject: mfd: stm32-timers: Use devm_of_platform_populate() Use devm_of_platform_populate() instead of of_platform_populate() and suppress stm32_timers_remove() which become useless. Signed-off-by: Benjamin Gaignard Signed-off-by: Lee Jones --- drivers/mfd/stm32-timers.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index 2182f00db101..a6675a449409 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -58,14 +58,7 @@ static int stm32_timers_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); -} - -static int stm32_timers_remove(struct platform_device *pdev) -{ - of_platform_depopulate(&pdev->dev); - - return 0; + return devm_of_platform_populate(&pdev->dev); } static const struct of_device_id stm32_timers_of_match[] = { @@ -76,7 +69,6 @@ MODULE_DEVICE_TABLE(of, stm32_timers_of_match); static struct platform_driver stm32_timers_driver = { .probe = stm32_timers_probe, - .remove = stm32_timers_remove, .driver = { .name = "stm32-timers", .of_match_table = stm32_timers_of_match, -- cgit v1.2.3 From ad56b2a4da907741236c612be913f28657962382 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:54 +0200 Subject: mfd: atmel: Use devm_of_platform_populate() Use devm_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/atmel-flexcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index e8e67be6b493..064bde9cff5a 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -80,7 +80,7 @@ static int atmel_flexcom_probe(struct platform_device *pdev) clk_disable_unprepare(clk); - return of_platform_populate(np, NULL, NULL, &pdev->dev); + return devm_of_platform_populate(&pdev->dev); } static const struct of_device_id atmel_flexcom_of_match[] = { -- cgit v1.2.3 From 2eb131efb13d1fb98c08fccfe25908a5a3ad04f6 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:55 +0200 Subject: mfd: cros_ec: Use devm_of_platform_populate() Use devm_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/cros_ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index d4a407e466b5..e31ac60a7623 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -147,7 +147,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) } if (IS_ENABLED(CONFIG_OF) && dev->of_node) { - err = of_platform_populate(dev->of_node, NULL, NULL, dev); + err = devm_of_platform_populate(dev); if (err) { mfd_remove_devices(dev); dev_err(dev, "Failed to register sub-devices\n"); -- cgit v1.2.3 From a55196eff6d63be4c439d707ce3b68ee82794ee9 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:57 +0200 Subject: mfd: fsl-imx25: Use devm_of_platform_populate() Use devm_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/fsl-imx25-tsadc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index 190e375dc57a..b3767c3141e5 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -129,7 +129,6 @@ static void mx25_tsadc_setup_clk(struct platform_device *pdev, static int mx25_tsadc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct mx25_tsadc *tsadc; struct resource *res; int ret; @@ -178,9 +177,7 @@ static int mx25_tsadc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tsadc); - of_platform_populate(np, NULL, NULL, dev); - - return 0; + return devm_of_platform_populate(dev); } static const struct of_device_id mx25_tsadc_ids[] = { -- cgit v1.2.3 From 11ee55d94e628a9931564372df23ae054834c38f Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:56 +0200 Subject: mfd: exynos: Use devm_of_platform_populate() Use devm_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/exynos-lpass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c index 0bf3aebdac45..ca829f85672f 100644 --- a/drivers/mfd/exynos-lpass.c +++ b/drivers/mfd/exynos-lpass.c @@ -138,7 +138,7 @@ static int exynos_lpass_probe(struct platform_device *pdev) pm_runtime_enable(dev); exynos_lpass_enable(lpass); - return of_platform_populate(dev->of_node, NULL, NULL, dev); + return devm_of_platform_populate(dev); } static int exynos_lpass_remove(struct platform_device *pdev) -- cgit v1.2.3 From 124e9deb1c40cc8c6fdf56bcb851500423eb9f13 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:59 +0200 Subject: mfd: palmas: Use devm_of_platform_populate() Use devm_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/palmas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 9103affedcbc..3922a93f9f92 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -676,7 +676,7 @@ no_irq: * otherwise continue and add devices using mfd helpers. */ if (node) { - ret = of_platform_populate(node, NULL, NULL, &i2c->dev); + ret = devm_of_platform_populate(&i2c->dev); if (ret < 0) { goto err_irq; } else if (pdata->pm_off && !pm_power_off) { -- cgit v1.2.3 From 6f00f8c8635f79b470eab6496265d63c1e1db3ed Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:46:00 +0200 Subject: mfd: qcom-spmi-pmic: Use devm_of_platform_populate() Usage of devm_of_platform_populate() simplify driver code by allowing to delete pmic_spmi_remove(). Signed-off-by: Benjamin Gaignard Signed-off-by: Lee Jones --- drivers/mfd/qcom-spmi-pmic.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 8653e8b9bb4f..2022bdfa7ab4 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -120,7 +120,6 @@ static const struct regmap_config spmi_regmap_config = { static int pmic_spmi_probe(struct spmi_device *sdev) { - struct device_node *root = sdev->dev.of_node; struct regmap *regmap; regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); @@ -131,19 +130,13 @@ static int pmic_spmi_probe(struct spmi_device *sdev) if (sdev->usid % 2 == 0) pmic_spmi_show_revid(regmap, &sdev->dev); - return of_platform_populate(root, NULL, NULL, &sdev->dev); -} - -static void pmic_spmi_remove(struct spmi_device *sdev) -{ - of_platform_depopulate(&sdev->dev); + return devm_of_platform_populate(&sdev->dev); } MODULE_DEVICE_TABLE(of, pmic_spmi_id_table); static struct spmi_driver pmic_spmi_driver = { .probe = pmic_spmi_probe, - .remove = pmic_spmi_remove, .driver = { .name = "pmic-spmi", .of_match_table = pmic_spmi_id_table, -- cgit v1.2.3 From 66002163f047884b8f245eb85249144e43168b92 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:46:01 +0200 Subject: mfd: smsc-ece: Use devm_of_platform_populate() Use devm_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/smsc-ece1099.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c index 1f40baf1234e..93a8297de52a 100644 --- a/drivers/mfd/smsc-ece1099.c +++ b/drivers/mfd/smsc-ece1099.c @@ -69,8 +69,7 @@ static int smsc_i2c_probe(struct i2c_client *i2c, #ifdef CONFIG_OF if (i2c->dev.of_node) - ret = of_platform_populate(i2c->dev.of_node, - NULL, NULL, &i2c->dev); + ret = devm_of_platform_populate(&i2c->dev); #endif return ret; -- cgit v1.2.3 From 9bf2db7834993b776707618ab5828265100bf3fd Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 May 2017 17:45:58 +0200 Subject: mfd: motorola-cpcap: Use devm_of_platform_populate() Usage of devm_of_platform_populate() simplify driver code by allowing to delete cpcap_remove(). Signed-off-by: Benjamin Gaignard Signed-off-by: Lee Jones --- drivers/mfd/motorola-cpcap.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c index 3cab58ab0b84..d2cc1eabac05 100644 --- a/drivers/mfd/motorola-cpcap.c +++ b/drivers/mfd/motorola-cpcap.c @@ -260,17 +260,7 @@ static int cpcap_probe(struct spi_device *spi) if (ret) return ret; - return of_platform_populate(spi->dev.of_node, NULL, NULL, - &cpcap->spi->dev); -} - -static int cpcap_remove(struct spi_device *pdev) -{ - struct cpcap_ddata *cpcap = spi_get_drvdata(pdev); - - of_platform_depopulate(&cpcap->spi->dev); - - return 0; + return devm_of_platform_populate(&cpcap->spi->dev); } static struct spi_driver cpcap_driver = { @@ -279,7 +269,6 @@ static struct spi_driver cpcap_driver = { .of_match_table = cpcap_of_match, }, .probe = cpcap_probe, - .remove = cpcap_remove, }; module_spi_driver(cpcap_driver); -- cgit v1.2.3 From b518d4adb83e3e139d3de96d172d9b4dec6def09 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 30 May 2017 10:17:40 +0200 Subject: mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving frequency Avoids reimplementation of DMI matching in intel_quark_i2c_setup. Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 7946d6e38b87..050061320377 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -58,19 +58,18 @@ struct intel_quark_mfd { struct clk_lookup *i2c_clk_lookup; }; -struct i2c_mode_info { - const char *name; - unsigned int i2c_scl_freq; -}; - -static const struct i2c_mode_info platform_i2c_mode_info[] = { +static const struct dmi_system_id dmi_platform_info[] = { { - .name = "Galileo", - .i2c_scl_freq = 100000, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), + }, + .driver_data = (void *)100000, }, { - .name = "GalileoGen2", - .i2c_scl_freq = 400000, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), + }, + .driver_data = (void *)400000, }, {} }; @@ -160,8 +159,7 @@ static void intel_quark_unregister_i2c_clk(struct device *dev) static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) { - const char *board_name = dmi_get_system_info(DMI_BOARD_NAME); - const struct i2c_mode_info *info; + const struct dmi_system_id *dmi_id; struct dw_i2c_platform_data *pdata; struct resource *res = (struct resource *)cell->resources; struct device *dev = &pdev->dev; @@ -181,14 +179,9 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) /* Normal mode by default */ pdata->i2c_scl_freq = 100000; - if (board_name) { - for (info = platform_i2c_mode_info; info->name; info++) { - if (!strcmp(board_name, info->name)) { - pdata->i2c_scl_freq = info->i2c_scl_freq; - break; - } - } - } + dmi_id = dmi_first_match(dmi_platform_info); + if (dmi_id) + pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data; cell->platform_data = pdata; cell->pdata_size = sizeof(*pdata); -- cgit v1.2.3 From 842086d2b5a6cec23d598edffb5137c72b265c50 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 30 May 2017 10:17:41 +0200 Subject: mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform The SIMATIC IOT2020 and IOT2040 are derived from the Galileo Gen2 board and share its I2C frequency. Signed-off-by: Sascha Weisenberger Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 050061320377..90e35dec8648 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -71,6 +71,22 @@ static const struct dmi_system_id dmi_platform_info[] = { }, .driver_data = (void *)400000, }, + { + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), + DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, + "6ES7647-0AA00-0YA2"), + }, + .driver_data = (void *)400000, + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), + DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, + "6ES7647-0AA00-1YA2"), + }, + .driver_data = (void *)400000, + }, {} }; -- cgit v1.2.3 From b6678050a1d9ce971bbb343607d3920efe7131a7 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 1 Jun 2017 12:44:50 +0530 Subject: mfd: tc6393xb: Handle return value of clk_prepare_enable clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Lee Jones --- drivers/mfd/tc6393xb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index d16e71bd9482..0c9f0390e891 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -797,7 +797,9 @@ static int tc6393xb_resume(struct platform_device *dev) int ret; int i; - clk_prepare_enable(tc6393xb->clk); + ret = clk_prepare_enable(tc6393xb->clk); + if (ret) + return ret; ret = tcpd->resume(dev); if (ret) -- cgit v1.2.3 From de85d79f4aab67fe0537dd6e2c5d545b88239cc4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Jun 2017 14:59:20 +0200 Subject: mfd: Add Cherry Trail Whiskey Cove PMIC driver Add mfd driver for Intel CHT Whiskey Cove PMIC, based on various non upstreamed CHT Whiskey Cove PMIC patches. This is a somewhat minimal version which adds irqchip support and cells for: ACPI PMIC opregion support, the i2c-controller driving the external charger irc and the pwrsrc/extcon block. Further cells can be added in the future if/when drivers are upstreamed for them. [The above patch caused a build error on some archetectures] From: Arnd Bergmann I ran into a build error on ARM with a platform that has a non-standard clk implementation: drivers/clk/clk.o: In function `clk_disable': clk.c:(.text.clk_disable+0x0): multiple definition of `clk_disable' arch/arm/mach-omap1/clock.o:clock.c:(.text.clk_disable+0x0): first defined here drivers/clk/clk.o: In function `clk_enable': clk.c:(.text.clk_enable+0x0): multiple definition of `clk_enable' arch/arm/mach-omap1/clock.o:clock.c:(.text.clk_enable+0x0): first defined here The problem is a device driver that uses 'select COMMON_CLK', which is generally a bad idea: selecting a subsystem should only be done from a platform, otherwise we run into circular dependencies. The same driver also selects 'GPIOLIB' and 'I2C', which has a similar effect. This turns all three into 'depends on', as it should be. Finally, we can limit the build to x86, unless we are compile testing. First patch: Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Fix for first patch (squashed): Signed-off-by: Arnd Bergmann Signed-off-by: Hans de Goede Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 16 +++ drivers/mfd/Makefile | 1 + drivers/mfd/intel_soc_pmic_chtwc.c | 230 +++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2ca88fc4698d..44e7164b5063 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -475,6 +475,22 @@ config INTEL_SOC_PMIC_BXTWC thermal, charger and related power management functions on these systems. +config INTEL_SOC_PMIC_CHTWC + tristate "Support for Intel Cherry Trail Whiskey Cove PMIC" + depends on ACPI && HAS_IOMEM && I2C=y && COMMON_CLK + depends on X86 || COMPILE_TEST + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + select I2C_DESIGNWARE_PLATFORM + help + Select this option to enable support for the Intel Cherry Trail + Whiskey Cove PMIC found on some Intel Cherry Trail systems. + + This option is a bool as it provides an ACPI OpRegion which must be + available before any devices using it are probed. This option also + causes the designware-i2c driver to be builtin for the same reason. + config MFD_INTEL_LPSS tristate select COMMON_CLK diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c16bf1ea0ea9..6f6aed8cfccc 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -214,6 +214,7 @@ obj-$(CONFIG_MFD_SKY81452) += sky81452.o 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_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c new file mode 100644 index 000000000000..b35da01d5bcf --- /dev/null +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -0,0 +1,230 @@ +/* + * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC + * + * Copyright (C) 2017 Hans de Goede + * + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. + * + * 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 + +/* PMIC device registers */ +#define REG_OFFSET_MASK GENMASK(7, 0) +#define REG_ADDR_MASK GENMASK(15, 8) +#define REG_ADDR_SHIFT 8 + +#define CHT_WC_IRQLVL1 0x6e02 +#define CHT_WC_IRQLVL1_MASK 0x6e0e + +/* Whiskey Cove PMIC share same ACPI ID between different platforms */ +#define CHT_WC_HRV 3 + +/* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */ +enum { + CHT_WC_PWRSRC_IRQ = 0, + CHT_WC_THRM_IRQ, + CHT_WC_BCU_IRQ, + CHT_WC_ADC_IRQ, + CHT_WC_EXT_CHGR_IRQ, + CHT_WC_GPIO_IRQ, + /* There is no irq 6 */ + CHT_WC_CRIT_IRQ = 7, +}; + +static struct resource cht_wc_pwrsrc_resources[] = { + DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ), +}; + +static struct resource cht_wc_ext_charger_resources[] = { + DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ), +}; + +static struct mfd_cell cht_wc_dev[] = { + { + .name = "cht_wcove_pwrsrc", + .num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources), + .resources = cht_wc_pwrsrc_resources, + }, { + .name = "cht_wcove_ext_chgr", + .num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources), + .resources = cht_wc_ext_charger_resources, + }, + { .name = "cht_wcove_region", }, +}; + +/* + * The CHT Whiskey Cove covers multiple I2C addresses, with a 1 Byte + * register address space per I2C address, so we use 16 bit register + * addresses where the high 8 bits contain the I2C client address. + */ +static int cht_wc_byte_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct i2c_client *client = context; + int ret, orig_addr = client->addr; + + if (!(reg & REG_ADDR_MASK)) { + dev_err(&client->dev, "Error I2C address not specified\n"); + return -EINVAL; + } + + client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; + ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK); + client->addr = orig_addr; + + if (ret < 0) + return ret; + + *val = ret; + return 0; +} + +static int cht_wc_byte_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct i2c_client *client = context; + int ret, orig_addr = client->addr; + + if (!(reg & REG_ADDR_MASK)) { + dev_err(&client->dev, "Error I2C address not specified\n"); + return -EINVAL; + } + + client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT; + ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val); + client->addr = orig_addr; + + return ret; +} + +static const struct regmap_config cht_wc_regmap_cfg = { + .reg_bits = 16, + .val_bits = 8, + .reg_write = cht_wc_byte_reg_write, + .reg_read = cht_wc_byte_reg_read, +}; + +static const struct regmap_irq cht_wc_regmap_irqs[] = { + REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)), + REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)), + REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)), + REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)), + REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)), + REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)), + REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)), +}; + +static const struct regmap_irq_chip cht_wc_regmap_irq_chip = { + .name = "cht_wc_irq_chip", + .status_base = CHT_WC_IRQLVL1, + .mask_base = CHT_WC_IRQLVL1_MASK, + .irqs = cht_wc_regmap_irqs, + .num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs), + .num_regs = 1, +}; + +static int cht_wc_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct intel_soc_pmic *pmic; + acpi_status status; + unsigned long long hrv; + int ret; + + status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to get PMIC hardware revision\n"); + return -ENODEV; + } + if (hrv != CHT_WC_HRV) { + dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv); + return -ENODEV; + } + if (client->irq < 0) { + dev_err(dev, "Invalid IRQ\n"); + return -EINVAL; + } + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + pmic->irq = client->irq; + pmic->dev = dev; + i2c_set_clientdata(client, pmic); + + pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg); + if (IS_ERR(pmic->regmap)) + return PTR_ERR(pmic->regmap); + + ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &cht_wc_regmap_irq_chip, + &pmic->irq_chip_data); + if (ret) + return ret; + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, + cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0, + regmap_irq_get_domain(pmic->irq_chip_data)); +} + +static void cht_wc_shutdown(struct i2c_client *client) +{ + struct intel_soc_pmic *pmic = i2c_get_clientdata(client); + + disable_irq(pmic->irq); +} + +static int __maybe_unused cht_wc_suspend(struct device *dev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + disable_irq(pmic->irq); + + return 0; +} + +static int __maybe_unused cht_wc_resume(struct device *dev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + enable_irq(pmic->irq); + + return 0; +} +static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); + +static const struct i2c_device_id cht_wc_i2c_id[] = { + { } +}; + +static const struct acpi_device_id cht_wc_acpi_ids[] = { + { "INT34D3", }, + { } +}; + +static struct i2c_driver cht_wc_driver = { + .driver = { + .name = "CHT Whiskey Cove PMIC", + .pm = &cht_wc_pm_ops, + .acpi_match_table = cht_wc_acpi_ids, + }, + .probe_new = cht_wc_probe, + .shutdown = cht_wc_shutdown, + .id_table = cht_wc_i2c_id, +}; +builtin_i2c_driver(cht_wc_driver); -- cgit v1.2.3 From aaac4a2eadaa6474a347ee4b07d4ea8bb6908c8e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Jun 2017 13:31:28 +0200 Subject: mfd: axp20x-i2c: Document that this must be builtin on x86 On x86 the AXP288 PMIC provides an ACPI OpRegion handler, which must be available before other drivers using it are loaded, which can only be ensured if the MFD, OpRegion and i2c-bus drivers are built-in. Since the AXP20x MFD code is used on non x86 too we cannot simply change this into a bool, I've tried some Kconfig magic with if x86 but I could not get this working correctly, so this commit just documents that this should be built-in on x86, which fixes errors like these during boot: mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-2 ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93 ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b acpi 80860F14:02: Failed to change power state to D0 Signed-off-by: Hans de Goede Acked-by: Chen-Yu Tsai Tested-by: russianneuromancer Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 44e7164b5063..1428814c33f9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -160,6 +160,11 @@ config MFD_AXP20X_I2C components like regulators or the PEK (Power Enable Key) under the corresponding menus. + Note on x86 this provides an ACPI OpRegion, so this must be 'y' + (builtin) and not a module, as the OpRegion must be available as + soon as possible. For the same reason the I2C bus driver options + I2C_DESIGNWARE_PLATFORM and I2C_DESIGNWARE_BAYTRAIL must be 'y' too. + config MFD_AXP20X_RSB tristate "X-Powers AXP series PMICs with RSB" select MFD_AXP20X -- cgit v1.2.3 From 2cd6496d81fbaa36d1c9387505000c05bf16e1c6 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Mon, 5 Jun 2017 15:35:10 +0100 Subject: mfd: da9061: Fix to remove BBAT_CONT register from chip model Remove the register DA9062AA_BBAT_CONT (0x0C5) from the DA9061 chip model regmap access ranges. This applies to both da9061_aa_readable_ranges[] and da9061_aa_writeable_ranges[]. This change is to correct the DA9061 chip model and align it with the latest DA9061 Datasheet. This register previously appeared in the DA9061 Datasheet, Revision 3.2, 01-Mar-2016 and has been removed from later DA9061 datasheet from Dialog, Revision 3.3, 04-Apr-2017. Signed-off-by: Steve Twiss Signed-off-by: Lee Jones --- drivers/mfd/da9062-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 7f5e8be0a9ea..fe1811523e4a 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -428,9 +428,6 @@ static const struct regmap_range da9061_aa_readable_ranges[] = { }, { .range_min = DA9062AA_VLDO1_B, .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_BBAT_CONT, - .range_max = DA9062AA_BBAT_CONT, }, { .range_min = DA9062AA_INTERFACE, .range_max = DA9062AA_CONFIG_E, @@ -513,9 +510,6 @@ static const struct regmap_range da9061_aa_writeable_ranges[] = { }, { .range_min = DA9062AA_VLDO1_B, .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_BBAT_CONT, - .range_max = DA9062AA_BBAT_CONT, }, { .range_min = DA9062AA_GP_ID_0, .range_max = DA9062AA_GP_ID_19, -- cgit v1.2.3 From b77eb79acca3203883e8d8dbc7f2b842def1bff8 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Mon, 5 Jun 2017 15:35:10 +0100 Subject: mfd: da9061: Fix to remove BBAT_CONT register from chip model Remove the register DA9062AA_BBAT_CONT (0x0C5) from the DA9061 chip model regmap access ranges. This applies to both da9061_aa_readable_ranges[] and da9061_aa_writeable_ranges[]. This change is to correct the DA9061 chip model and align it with the latest DA9061 Datasheet. This register previously appeared in the DA9061 Datasheet, Revision 3.2, 01-Mar-2016 and has been removed from later DA9061 datasheet from Dialog, Revision 3.3, 04-Apr-2017. Signed-off-by: Steve Twiss Signed-off-by: Lee Jones --- drivers/mfd/da9062-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index fe1811523e4a..fbe0f245ce8e 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -644,9 +644,6 @@ static const struct regmap_range da9062_aa_readable_ranges[] = { }, { .range_min = DA9062AA_VLDO1_B, .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_BBAT_CONT, - .range_max = DA9062AA_BBAT_CONT, }, { .range_min = DA9062AA_INTERFACE, .range_max = DA9062AA_CONFIG_E, @@ -723,9 +720,6 @@ static const struct regmap_range da9062_aa_writeable_ranges[] = { }, { .range_min = DA9062AA_VLDO1_B, .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_BBAT_CONT, - .range_max = DA9062AA_BBAT_CONT, }, { .range_min = DA9062AA_GP_ID_0, .range_max = DA9062AA_GP_ID_19, -- cgit v1.2.3 From f58b14e6632a07ea1eb89aedb5e27cc55d251826 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 12 Jun 2017 16:42:46 +0800 Subject: mfd: cros_ec: Free IRQ on exit Currently we request the irq when probing, but never free it. So after unbind ec driver, this irq will be left requested, which would break the next bind: [ 2683.338437] genirq: Flags mismatch irq 64. 00002008 (chromeos-ec) vs. 00002008 (chromeos-ec) [ 2683.338591] cros-ec-spi spi5.0: request irq 64: error -16 [ 2683.338610] cros-ec-spi spi5.0: cannot register EC [ 2683.338656] cros-ec-spi: probe of spi5.0 failed with error -16 Signed-off-by: Jeffy Chen Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index e31ac60a7623..dc6ce9091694 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -183,6 +183,9 @@ int cros_ec_remove(struct cros_ec_device *ec_dev) cros_ec_acpi_remove_gpe_handler(); + if (ec_dev->irq) + free_irq(ec_dev->irq, ec_dev); + return 0; } EXPORT_SYMBOL(cros_ec_remove); -- cgit v1.2.3 From 1e3496000c11ec1ec56cf664b6a01d66de423507 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 13 Jun 2017 10:28:40 +0530 Subject: mfd: Add LP87565 PMIC support The LP87565 chip is a power management IC for Portable Navigation Systems and Tablet Computing devices. It contains the following components: - Configurable Bucks(Single and multi-phase). - Configurable General Purpose Output Signals (GPO). The LP87565-Q1 variant device uses two 2-phase outputs configuration, Buck0 is master for Buck0/1 output and Buck2 is master for Buck2/3 output. Signed-off-by: Keerthy Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/lp87565.txt | 43 ++++ drivers/mfd/Kconfig | 14 ++ drivers/mfd/Makefile | 1 + drivers/mfd/lp87565.c | 100 ++++++++ include/linux/mfd/lp87565.h | 270 ++++++++++++++++++++++ 5 files changed, 428 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/lp87565.txt create mode 100644 drivers/mfd/lp87565.c create mode 100644 include/linux/mfd/lp87565.h (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mfd/lp87565.txt b/Documentation/devicetree/bindings/mfd/lp87565.txt new file mode 100644 index 000000000000..a48df7c08ab0 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/lp87565.txt @@ -0,0 +1,43 @@ +TI LP87565 PMIC MFD driver + +Required properties: + - compatible: "ti,lp87565", "ti,lp87565-q1" + - reg: I2C slave address. + - gpio-controller: Marks the device node as a GPIO Controller. + - #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - xxx-in-supply: Phandle to parent supply node of each regulator + populated under regulators node. xxx should match + the supply_name populated in driver. +Example: + +lp87565_pmic: pmic@60 { + compatible = "ti,lp87565-q1"; + reg = <0x60>; + gpio-controller; + #gpio-cells = <2>; + + buck10-in-supply = <&vsys_3v3>; + buck23-in-supply = <&vsys_3v3>; + + regulators: regulators { + buck10_reg: buck10 { + /* VDD_MPU */ + regulator-name = "buck10"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1250000>; + regulator-always-on; + regulator-boot-on; + }; + + buck23_reg: buck23 { + /* VDD_GPU */ + regulator-name = "buck23"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1250000>; + regulator-boot-on; + regulator-always-on; + }; + }; +}; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1428814c33f9..94ad2c1c3d90 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1351,6 +1351,20 @@ config MFD_TI_LP873X This driver can also be built as a module. If so, the module will be called lp873x. +config MFD_TI_LP87565 + tristate "TI LP87565 Power Management IC" + depends on I2C && OF + select MFD_CORE + select REGMAP_I2C + help + If you say yes here then you get support for the LP87565 series of + Power Management Integrated Circuits (PMIC). + These include voltage regulators, thermal protection, configurable + General Purpose Outputs (GPO) that are used in portable devices. + + This driver can also be built as a module. If so, the module + will be called lp87565. + config MFD_TPS65218 tristate "TI TPS65218 Power Management chips" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 6f6aed8cfccc..080793b3fd0e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o +obj-$(CONFIG_MFD_TI_LP87565) += lp87565.o obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c new file mode 100644 index 000000000000..340ad0c63744 --- /dev/null +++ b/drivers/mfd/lp87565.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * Author: Keerthy + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + */ + +#include +#include +#include +#include +#include + +#include + +static const struct regmap_config lp87565_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LP87565_REG_MAX, +}; + +static const struct mfd_cell lp87565_cells[] = { + { .name = "lp87565-q1-regulator", }, + { .name = "lp87565-q1-gpio", }, +}; + +static const struct of_device_id of_lp87565_match_table[] = { + { .compatible = "ti,lp87565", }, + { + .compatible = "ti,lp87565-q1", + .data = (void *)LP87565_DEVICE_TYPE_LP87565_Q1, + }, + {} +}; +MODULE_DEVICE_TABLE(of, of_lp87565_match_table); + +static int lp87565_probe(struct i2c_client *client, + const struct i2c_device_id *ids) +{ + struct lp87565 *lp87565; + const struct of_device_id *of_id; + int ret; + unsigned int otpid; + + lp87565 = devm_kzalloc(&client->dev, sizeof(*lp87565), GFP_KERNEL); + if (!lp87565) + return -ENOMEM; + + lp87565->dev = &client->dev; + + lp87565->regmap = devm_regmap_init_i2c(client, &lp87565_regmap_config); + if (IS_ERR(lp87565->regmap)) { + ret = PTR_ERR(lp87565->regmap); + dev_err(lp87565->dev, + "Failed to initialize register map: %d\n", ret); + return ret; + } + + ret = regmap_read(lp87565->regmap, LP87565_REG_OTP_REV, &otpid); + if (ret) { + dev_err(lp87565->dev, "Failed to read OTP ID\n"); + return ret; + } + + lp87565->rev = otpid & LP87565_OTP_REV_OTP_ID; + + of_id = of_match_device(of_lp87565_match_table, &client->dev); + if (of_id) + lp87565->dev_type = (enum lp87565_device_type)of_id->data; + + i2c_set_clientdata(client, lp87565); + + ret = mfd_add_devices(lp87565->dev, PLATFORM_DEVID_AUTO, lp87565_cells, + ARRAY_SIZE(lp87565_cells), NULL, 0, NULL); + + return ret; +} + +static const struct i2c_device_id lp87565_id_table[] = { + { "lp87565-q1", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, lp87565_id_table); + +static struct i2c_driver lp87565_driver = { + .driver = { + .name = "lp87565", + .of_match_table = of_lp87565_match_table, + }, + .probe = lp87565_probe, + .id_table = lp87565_id_table, +}; +module_i2c_driver(lp87565_driver); + +MODULE_AUTHOR("J Keerthy "); +MODULE_DESCRIPTION("lp87565 chip family Multi-Function Device driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/lp87565.h b/include/linux/mfd/lp87565.h new file mode 100644 index 000000000000..d0c91ba65525 --- /dev/null +++ b/include/linux/mfd/lp87565.h @@ -0,0 +1,270 @@ +/* + * Functions to access LP87565 power management chip. + * + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + */ + +#ifndef __LINUX_MFD_LP87565_H +#define __LINUX_MFD_LP87565_H + +#include +#include +#include + +enum lp87565_device_type { + LP87565_DEVICE_TYPE_UNKNOWN = 0, + LP87565_DEVICE_TYPE_LP87565_Q1, +}; + +/* All register addresses */ +#define LP87565_REG_DEV_REV 0X00 +#define LP87565_REG_OTP_REV 0X01 +#define LP87565_REG_BUCK0_CTRL_1 0X02 +#define LP87565_REG_BUCK0_CTRL_2 0X03 + +#define LP87565_REG_BUCK1_CTRL_1 0X04 +#define LP87565_REG_BUCK1_CTRL_2 0X05 + +#define LP87565_REG_BUCK2_CTRL_1 0X06 +#define LP87565_REG_BUCK2_CTRL_2 0X07 + +#define LP87565_REG_BUCK3_CTRL_1 0X08 +#define LP87565_REG_BUCK3_CTRL_2 0X09 + +#define LP87565_REG_BUCK0_VOUT 0X0A +#define LP87565_REG_BUCK0_FLOOR_VOUT 0X0B + +#define LP87565_REG_BUCK1_VOUT 0X0C +#define LP87565_REG_BUCK1_FLOOR_VOUT 0X0D + +#define LP87565_REG_BUCK2_VOUT 0X0E +#define LP87565_REG_BUCK2_FLOOR_VOUT 0X0F + +#define LP87565_REG_BUCK3_VOUT 0X10 +#define LP87565_REG_BUCK3_FLOOR_VOUT 0X11 + +#define LP87565_REG_BUCK0_DELAY 0X12 +#define LP87565_REG_BUCK1_DELAY 0X13 + +#define LP87565_REG_BUCK2_DELAY 0X14 +#define LP87565_REG_BUCK3_DELAY 0X15 + +#define LP87565_REG_GPO2_DELAY 0X16 +#define LP87565_REG_GPO3_DELAY 0X17 +#define LP87565_REG_RESET 0X18 +#define LP87565_REG_CONFIG 0X19 + +#define LP87565_REG_INT_TOP_1 0X1A +#define LP87565_REG_INT_TOP_2 0X1B + +#define LP87565_REG_INT_BUCK_0_1 0X1C +#define LP87565_REG_INT_BUCK_2_3 0X1D +#define LP87565_REG_TOP_STAT 0X1E +#define LP87565_REG_BUCK_0_1_STAT 0X1F +#define LP87565_REG_BUCK_2_3_STAT 0x20 + +#define LP87565_REG_TOP_MASK_1 0x21 +#define LP87565_REG_TOP_MASK_2 0x22 + +#define LP87565_REG_BUCK_0_1_MASK 0x23 +#define LP87565_REG_BUCK_2_3_MASK 0x24 +#define LP87565_REG_SEL_I_LOAD 0x25 + +#define LP87565_REG_I_LOAD_2 0x26 +#define LP87565_REG_I_LOAD_1 0x27 + +#define LP87565_REG_PGOOD_CTRL1 0x28 +#define LP87565_REG_PGOOD_CTRL2 0x29 +#define LP87565_REG_PGOOD_FLT 0x2A +#define LP87565_REG_PLL_CTRL 0x2B +#define LP87565_REG_PIN_FUNCTION 0x2C +#define LP87565_REG_GPIO_CONFIG 0x2D +#define LP87565_REG_GPIO_IN 0x2E +#define LP87565_REG_GPIO_OUT 0x2F + +#define LP87565_REG_MAX LP87565_REG_GPIO_OUT + +/* Register field definitions */ +#define LP87565_DEV_REV_DEV_ID 0xC0 +#define LP87565_DEV_REV_ALL_LAYER 0x30 +#define LP87565_DEV_REV_METAL_LAYER 0x0F + +#define LP87565_OTP_REV_OTP_ID 0xFF + +#define LP87565_BUCK_CTRL_1_EN BIT(7) +#define LP87565_BUCK_CTRL_1_EN_PIN_CTRL BIT(6) +#define LP87565_BUCK_CTRL_1_PIN_SELECT_EN 0x30 + +#define LP87565_BUCK_CTRL_1_ROOF_FLOOR_EN BIT(3) +#define LP87565_BUCK_CTRL_1_RDIS_EN BIT(2) +#define LP87565_BUCK_CTRL_1_FPWM BIT(1) +/* Bit0 is reserved for BUCK1 and BUCK3 and valid only for BUCK0 and BUCK2 */ +#define LP87565_BUCK_CTRL_1_FPWM_MP_0_2 BIT(0) + +#define LP87565_BUCK_CTRL_2_ILIM 0x38 +#define LP87565_BUCK_CTRL_2_SLEW_RATE 0x07 + +#define LP87565_BUCK_VSET 0xFF +#define LP87565_BUCK_FLOOR_VSET 0xFF + +#define LP87565_BUCK_SHUTDOWN_DELAY 0xF0 +#define LP87565_BUCK_STARTUP_DELAY 0x0F + +#define LP87565_GPIO_SHUTDOWN_DELAY 0xF0 +#define LP87565_GPIO_STARTUP_DELAY 0x0F + +#define LP87565_RESET_SW_RESET BIT(0) + +#define LP87565_CONFIG_DOUBLE_DELAY BIT(7) +#define LP87565_CONFIG_CLKIN_PD BIT(6) +#define LP87565_CONFIG_EN4_PD BIT(5) +#define LP87565_CONFIG_EN3_PD BIT(4) +#define LP87565_CONFIG_TDIE_WARN_LEVEL BIT(3) +#define LP87565_CONFIG_EN2_PD BIT(2) +#define LP87565_CONFIG_EN1_PD BIT(1) + +#define LP87565_INT_GPIO BIT(7) +#define LP87565_INT_BUCK23 BIT(6) +#define LP87565_INT_BUCK01 BIT(5) +#define LP87565_NO_SYNC_CLK BIT(4) +#define LP87565_TDIE_SD BIT(3) +#define LP87565_TDIE_WARN BIT(2) +#define LP87565_INT_OVP BIT(1) +#define LP87565_I_LOAD_READY BIT(0) + +#define LP87565_INT_TOP2_RESET_REG BIT(0) + +#define LP87565_BUCK1_PG_INT BIT(6) +#define LP87565_BUCK1_SC_INT BIT(5) +#define LP87565_BUCK1_ILIM_INT BIT(4) +#define LP87565_BUCK0_PG_INT BIT(2) +#define LP87565_BUCK0_SC_INT BIT(1) +#define LP87565_BUCK0_ILIM_INT BIT(0) + +#define LP87565_BUCK3_PG_INT BIT(6) +#define LP87565_BUCK3_SC_INT BIT(5) +#define LP87565_BUCK3_ILIM_INT BIT(4) +#define LP87565_BUCK2_PG_INT BIT(2) +#define LP87565_BUCK2_SC_INT BIT(1) +#define LP87565_BUCK2_ILIM_INT BIT(0) + +#define LP87565_SYNC_CLK_STAT BIT(4) +#define LP87565_TDIE_SD_STAT BIT(3) +#define LP87565_TDIE_WARN_STAT BIT(2) +#define LP87565_OVP_STAT BIT(1) + +#define LP87565_BUCK1_STAT BIT(7) +#define LP87565_BUCK1_PG_STAT BIT(6) +#define LP87565_BUCK1_ILIM_STAT BIT(4) +#define LP87565_BUCK0_STAT BIT(3) +#define LP87565_BUCK0_PG_STAT BIT(2) +#define LP87565_BUCK0_ILIM_STAT BIT(0) + +#define LP87565_BUCK3_STAT BIT(7) +#define LP87565_BUCK3_PG_STAT BIT(6) +#define LP87565_BUCK3_ILIM_STAT BIT(4) +#define LP87565_BUCK2_STAT BIT(3) +#define LP87565_BUCK2_PG_STAT BIT(2) +#define LP87565_BUCK2_ILIM_STAT BIT(0) + +#define LPL87565_GPIO_MASK BIT(7) +#define LPL87565_SYNC_CLK_MASK BIT(4) +#define LPL87565_TDIE_WARN_MASK BIT(2) +#define LPL87565_I_LOAD_READY_MASK BIT(0) + +#define LPL87565_RESET_REG_MASK BIT(0) + +#define LPL87565_BUCK1_PG_MASK BIT(6) +#define LPL87565_BUCK1_ILIM_MASK BIT(4) +#define LPL87565_BUCK0_PG_MASK BIT(2) +#define LPL87565_BUCK0_ILIM_MASK BIT(0) + +#define LPL87565_BUCK3_PG_MASK BIT(6) +#define LPL87565_BUCK3_ILIM_MASK BIT(4) +#define LPL87565_BUCK2_PG_MASK BIT(2) +#define LPL87565_BUCK2_ILIM_MASK BIT(0) + +#define LP87565_LOAD_CURRENT_BUCK_SELECT 0x3 + +#define LP87565_I_LOAD2_BUCK_LOAD_CURRENT 0x3 +#define LP87565_I_LOAD1_BUCK_LOAD_CURRENT 0xFF + +#define LP87565_PG3_SEL 0xC0 +#define LP87565_PG2_SEL 0x30 +#define LP87565_PG1_SEL 0x0C +#define LP87565_PG0_SEL 0x03 + +#define LP87565_HALF_DAY BIT(7) +#define LP87565_EN_PG0_NINT BIT(6) +#define LP87565_PGOOD_SET_DELAY BIT(5) +#define LP87565_EN_PGFLT_STAT BIT(4) +#define LP87565_PGOOD_WINDOW BIT(2) +#define LP87565_PGOOD_OD BIT(1) +#define LP87565_PGOOD_POL BIT(0) + +#define LP87565_PG3_FLT BIT(3) +#define LP87565_PG2_FLT BIT(2) +#define LP87565_PG1_FLT BIT(1) +#define LP87565_PG0_FLT BIT(0) + +#define LP87565_PLL_MODE 0xC0 +#define LP87565_EXT_CLK_FREQ 0x1F + +#define LP87565_EN_SPREAD_SPEC BIT(7) +#define LP87565_EN_PIN_CTRL_GPIO3 BIT(6) +#define LP87565_EN_PIN_SELECT_GPIO3 BIT(5) +#define LP87565_EN_PIN_CTRL_GPIO2 BIT(4) +#define LP87565_EN_PIN_SELECT_GPIO2 BIT(3) +#define LP87565_GPIO3_SEL BIT(2) +#define LP87565_GPIO2_SEL BIT(1) +#define LP87565_GPIO1_SEL BIT(0) + +#define LP87565_GOIO3_OD BIT(6) +#define LP87565_GOIO2_OD BIT(5) +#define LP87565_GOIO1_OD BIT(4) +#define LP87565_GOIO3_DIR BIT(2) +#define LP87565_GOIO2_DIR BIT(1) +#define LP87565_GOIO1_DIR BIT(0) + +#define LP87565_GOIO3_IN BIT(2) +#define LP87565_GOIO2_IN BIT(1) +#define LP87565_GOIO1_IN BIT(0) + +#define LP87565_GOIO3_OUT BIT(2) +#define LP87565_GOIO2_OUT BIT(1) +#define LP87565_GOIO1_OUT BIT(0) + +/* Number of step-down converters available */ +#define LP87565_NUM_BUCK 6 + +enum LP87565_regulator_id { + /* BUCK's */ + LP87565_BUCK_0, + LP87565_BUCK_1, + LP87565_BUCK_2, + LP87565_BUCK_3, + LP87565_BUCK_10, + LP87565_BUCK_23, +}; + +/** + * struct LP87565 - state holder for the LP87565 driver + * @dev: struct device pointer for MFD device + * @rev: revision of the LP87565 + * @dev_type: The device type for example lp87565-q1 + * @lock: lock guarding the data structure + * @regmap: register map of the LP87565 PMIC + * + * Device data may be used to access the LP87565 chip + */ +struct lp87565 { + struct device *dev; + u8 rev; + u8 dev_type; + struct regmap *regmap; +}; +#endif /* __LINUX_MFD_LP87565_H */ -- cgit v1.2.3