From aed35270f0be1c5c61a028d7c183e60269f3abe3 Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Mon, 26 Nov 2018 14:41:37 +0100 Subject: [PATCH 22/52] ARM-stm32mp1-r0-rc2-MFD-IRQ --- .../interrupt-controller/st,stm32-exti.txt | 34 +++++- .../devicetree/bindings/mfd/st,stpmic1.txt | 2 +- Documentation/devicetree/bindings/mfd/syscon.txt | 1 + drivers/irqchip/irq-stm32-exti.c | 133 ++++++++++++++++++--- drivers/mfd/stm32-pwr.c | 131 +++++++++----------- drivers/mfd/stpmic1.c | 16 +-- drivers/mfd/syscon.c | 19 +++ drivers/mfd/wm8994-core.c | 15 +++ include/linux/mfd/stpmic1.h | 1 - 9 files changed, 247 insertions(+), 105 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt index 6a36bf6..abcf816 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt @@ -14,7 +14,23 @@ Required properties: (only needed for exti controller with multiple exti under same parent interrupt: st,stm32-exti and st,stm32h7-exti) -Example: +Optional properties: + +- hwlocks: reference to a phandle of a hardware spinlock provider node. + +Exti could have several parent interrupt controllers. In this case child nodes +are used to describe those "extra" parent controllers. Properties to use are: + +- interrupt-controller: Indentifies the node as an interrupt controller +- #interrupt-cells: Specifies the number of cells to encode an interrupt + specifier, shall be 2 +- interrupt-parent: Phandle to the interrupt parent node. +- st,irq-number: Interrupt number mapped on the parent. + +See example 2. + + +Example 1: exti: interrupt-controller@40013c00 { compatible = "st,stm32-exti"; @@ -23,3 +39,19 @@ exti: interrupt-controller@40013c00 { reg = <0x40013C00 0x400>; interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>; }; + +Example 2: + +exti: interrupt-controller@5000d000 { + compatible = "st,stm32mp1-exti", "syscon"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x5000d000 0x400>; + + exti_pwr: exti-pwr { + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&pwr>; + st,irq-number = <6>; + }; +}; diff --git a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt index 54b64e2..0fab08a 100644 --- a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt +++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt @@ -4,7 +4,6 @@ Required parent device properties: - compatible: "st,stpmic1" - reg: The I2C slave address for the STPMIC1 chip. - interrupts: The interrupt lines the device is connected to. - The second interrupt is used for wake-up. - #interrupt-cells: Should be 2. - interrupt-controller: Describes the STPMIC1 as an interrupt controller (has its own domain). Interrupt number are the following: @@ -81,6 +80,7 @@ Optional parent device properties: -bit 5: SW_OUT discharge is enabled -bit 6: VBUS_OTG detection is enabled -bit 7: BOOST_OVP is disabled +- wakeup-source: bool flag to indicate this device has wakeup capabilities STPMIC1 consists in a varied group of sub-devices. Each sub-device binding is be described in own documentation file. diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt index 25d9e9c..a9aaa51 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.txt +++ b/Documentation/devicetree/bindings/mfd/syscon.txt @@ -17,6 +17,7 @@ Optional property: - reg-io-width: the size (in bytes) of the IO accesses that should be performed on the device. - hwlocks: reference to a phandle of a hardware spinlock provider node. +- clocks: phandle to the syscon clock Examples: gpr: iomuxc-gpr@20e0000 { diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index e185ed8..9cc15f1 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -20,6 +21,8 @@ #define IRQS_PER_BANK 32 +#define HWSPINLOCK_TIMEOUT 5 /* msec */ + struct stm32_exti_bank { u32 imr_ofst; u32 emr_ofst; @@ -47,6 +50,7 @@ struct stm32_exti_drv_data { struct stm32_exti_chip_data { struct stm32_exti_host_data *host_data; const struct stm32_exti_bank *reg_bank; + struct hwspinlock *hwlock; struct raw_spinlock rlock; u32 wake_active; u32 mask_cache; @@ -275,25 +279,34 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) struct stm32_exti_chip_data *chip_data = gc->private; const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; u32 rtsr, ftsr; - int err; + int err = 0; irq_gc_lock(gc); + if (chip_data->hwlock) + err = hwspin_lock_timeout(chip_data->hwlock, + HWSPINLOCK_TIMEOUT); + + if (err) + goto unlock; + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); err = stm32_exti_set_type(d, type, &rtsr, &ftsr); - if (err) { - irq_gc_unlock(gc); - return err; - } + if (err) + goto unspinlock; irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); +unspinlock: + if (chip_data->hwlock) + hwspin_unlock(chip_data->hwlock); +unlock: irq_gc_unlock(gc); - return 0; + return err; } static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data, @@ -457,22 +470,36 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; void __iomem *base = chip_data->host_data->base; u32 rtsr, ftsr; - int err; + int err = 0; raw_spin_lock(&chip_data->rlock); + + if (chip_data->hwlock) + err = hwspin_lock_timeout(chip_data->hwlock, + HWSPINLOCK_TIMEOUT); + + if (err) + goto unlock; + rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); err = stm32_exti_set_type(d, type, &rtsr, &ftsr); - if (err) { - raw_spin_unlock(&chip_data->rlock); - return err; - } + if (err) + goto unspinlock; writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst); writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); + +unspinlock: + if (chip_data->hwlock) + hwspin_unlock(chip_data->hwlock); +unlock: raw_spin_unlock(&chip_data->rlock); + if (d->parent_data->chip) + irq_chip_set_type_parent(d, type); + return 0; } @@ -490,6 +517,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) raw_spin_unlock(&chip_data->rlock); + if (d->parent_data->chip) + irq_chip_set_wake_parent(d, on); + return 0; } @@ -502,6 +532,12 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, return -EINVAL; } +static void stm32_exti_h_ack(struct irq_data *d) +{ + if (d->parent_data->chip) + irq_chip_ack_parent(d); +} + #ifdef CONFIG_PM static int stm32_exti_h_suspend(void) { @@ -547,6 +583,7 @@ static inline void stm32_exti_h_syscore_init(void) {} static struct irq_chip stm32_exti_h_chip = { .name = "stm32-exti-h", .irq_eoi = stm32_exti_h_eoi, + .irq_ack = stm32_exti_h_ack, .irq_mask = stm32_exti_h_mask, .irq_unmask = stm32_exti_h_unmask, .irq_retrigger = irq_chip_retrigger_hierarchy, @@ -574,15 +611,29 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm, irq_domain_set_hwirq_and_chip(dm, virq, hwirq, &stm32_exti_h_chip, chip_data); - p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); - if (p_irq >= 0) { + /* + * EXTI 55 to 60 are mapped to PWR interrupt controller. + * The hwirq translation is done diferently than for GIC. + */ + if (hwirq >= 55 && hwirq <= 60) { p_fwspec.fwnode = dm->parent->fwnode; - p_fwspec.param_count = 3; - p_fwspec.param[0] = GIC_SPI; - p_fwspec.param[1] = p_irq; - p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; + p_fwspec.param_count = 2; + p_fwspec.param[0] = hwirq - 55; + p_fwspec.param[1] = fwspec->param[1]; return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); + } else { + p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); + if (p_irq >= 0) { + p_fwspec.fwnode = dm->parent->fwnode; + p_fwspec.param_count = 3; + p_fwspec.param[0] = GIC_SPI; + p_fwspec.param[1] = p_irq; + p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; + + return irq_domain_alloc_irqs_parent(dm, virq, 1, + &p_fwspec); + } } return 0; @@ -665,6 +716,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, int nr_irqs, ret, i; struct irq_chip_generic *gc; struct irq_domain *domain; + struct hwspinlock *hwlock = NULL; host_data = stm32_exti_host_init(drv_data, node); if (!host_data) @@ -687,12 +739,22 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, goto out_free_domain; } + /* hwspinlock is optional */ + ret = of_hwspin_lock_get_id(node, 0); + if (ret < 0) { + if (ret == -EPROBE_DEFER) + goto out_free_domain; + } else { + hwlock = hwspin_lock_request_specific(ret); + } + for (i = 0; i < drv_data->bank_nr; i++) { const struct stm32_exti_bank *stm32_bank; struct stm32_exti_chip_data *chip_data; stm32_bank = drv_data->exti_banks[i]; chip_data = stm32_exti_chip_init(host_data, i, node); + chip_data->hwlock = hwlock; gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); @@ -760,11 +822,12 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, { struct irq_domain *parent_domain, *domain; struct stm32_exti_host_data *host_data; + struct device_node *child; int ret, i; parent_domain = irq_find_host(parent); if (!parent_domain) { - pr_err("interrupt-parent not found\n"); + pr_err("GIC interrupt-parent not found\n"); return -EINVAL; } @@ -786,6 +849,40 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, goto out_unmap; } + for_each_child_of_node(node, child) { + struct device_node *parent_node; + u32 nirqs; + + parent_node = of_irq_find_parent(child); + parent_domain = irq_find_host(parent_node); + + if (!parent_domain) { + pr_err("%s: child interrupt-parent not found\n", + child->name); + ret = -EINVAL; + goto out_unmap; + } + + ret = of_property_read_u32(child, "st,irq-number", &nirqs); + if (ret != 0 || nirqs == 0) { + pr_err("%s: Missing or bad irq-number property\n" + , __func__); + ret = -EINVAL; + goto out_unmap; + } + + domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs, + child, + &stm32_exti_h_domain_ops, + host_data); + if (!domain) { + pr_err("%s: Could not register exti domain.\n", + node->name); + ret = -ENOMEM; + goto out_unmap; + } + } + stm32_exti_h_syscore_init(); return 0; diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c index 377e2f5..206a933 100644 --- a/drivers/mfd/stm32-pwr.c +++ b/drivers/mfd/stm32-pwr.c @@ -5,7 +5,9 @@ */ #include +#include #include +#include #include #include #include @@ -45,7 +47,6 @@ enum wkup_pull_setting { } \ struct stm32_pwr_data { - struct device *dev; /* self device */ void __iomem *base; /* IO Memory base address */ struct irq_domain *domain; /* Domain for this controller */ int irq; /* Parent interrupt */ @@ -53,25 +54,19 @@ struct stm32_pwr_data { static void stm32_pwr_irq_ack(struct irq_data *d) { - struct stm32_pwr_data *priv = d->domain->host_data; - - dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); + pr_debug("irq:%lu\n", d->hwirq); SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, BIT(d->hwirq)); } static void stm32_pwr_irq_mask(struct irq_data *d) { - struct stm32_pwr_data *priv = d->domain->host_data; - - dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); + pr_debug("irq:%lu\n", d->hwirq); SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq)); } static void stm32_pwr_irq_unmask(struct irq_data *d) { - struct stm32_pwr_data *priv = d->domain->host_data; - - dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); + pr_debug("irq:%lu\n", d->hwirq); SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq)); } @@ -79,7 +74,7 @@ static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on) { struct stm32_pwr_data *priv = d->domain->host_data; - dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on); + pr_debug("irq:%lu on:%d\n", d->hwirq, on); if (on) enable_irq_wake(priv->irq); else @@ -95,7 +90,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) u32 wkupcr; int en; - dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); + pr_debug("irq:%lu\n", d->hwirq); en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id); /* reference manual request to disable the wakeup pin while @@ -115,6 +110,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) default: return -EINVAL; } + SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); if (en) @@ -124,7 +120,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) } static struct irq_chip stm32_pwr_irq_chip = { - .name = "stm32_pwr-irq", + .name = "stm32-pwr-irq", .irq_ack = stm32_pwr_irq_ack, .irq_mask = stm32_pwr_irq_mask, .irq_unmask = stm32_pwr_irq_unmask, @@ -132,29 +128,23 @@ static struct irq_chip stm32_pwr_irq_chip = { .irq_set_wake = stm32_pwr_irq_set_wake, }; -static int stm32_pwr_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - irq_set_chip_and_handler(virq, &stm32_pwr_irq_chip, handle_edge_irq); - return 0; -} - static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id, enum wkup_pull_setting config) { struct stm32_pwr_data *priv = d->host_data; u32 wkupcr; - dev_dbg(priv->dev, "irq:%d pull config:0x%x\n", pin_id, config); + pr_debug("irq:%d pull config:0x%x\n", pin_id, config); if (config >= WKUP_PULL_RESERVED) { - dev_err(priv->dev, "%s: bad irq pull config\n", __func__); + pr_err("%s: bad irq pull config\n", __func__); return -EINVAL; } wkupcr = readl_relaxed(priv->base + WKUPCR); wkupcr &= ~((WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2)); wkupcr |= (config & WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2); + SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); return 0; @@ -164,10 +154,8 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - struct stm32_pwr_data *priv = d->host_data; - if (WARN_ON(intsize < 3)) { - dev_err(priv->dev, "%s: bad irq config parameters\n", __func__); + pr_err("%s: bad irq config parameters\n", __func__); return -EINVAL; } @@ -177,9 +165,23 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr, return stm32_pwr_irq_set_pull_config(d, intspec[0], intspec[2]); } +static int stm32_pwr_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct irq_fwspec *fwspec = data; + irq_hw_number_t hwirq; + + hwirq = fwspec->param[0]; + irq_domain_set_info(d, virq, hwirq, &stm32_pwr_irq_chip, d->host_data, + handle_edge_irq, NULL, NULL); + + return 0; +} + static const struct irq_domain_ops stm32_pwr_irq_domain_ops = { - .map = stm32_pwr_irq_map, + .alloc = stm32_pwr_alloc, .xlate = stm32_pwr_xlate, + .free = irq_domain_free_irqs_common, }; /* @@ -195,9 +197,10 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc) wkupfr = readl_relaxed(priv->base + WKUPFR); wkupenr = readl_relaxed(priv->base + MPUWKUPENR); + for (i = 0; i < NB_WAKEUPPINS; i++) { if ((wkupfr & BIT(i)) && (wkupenr & BIT(i))) { - dev_dbg(priv->dev, "handle wkup irq:%d\n", i); + pr_debug("handle wkup irq:%d\n", i); generic_handle_irq(irq_find_mapping(priv->domain, i)); } } @@ -205,27 +208,21 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int stm32_pwr_probe(struct platform_device *pdev) +static int __init stm32_pwr_init(struct device_node *np, + struct device_node *parent) { - struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; struct stm32_pwr_data *priv; - - struct resource *res; int ret; - priv = devm_kzalloc(dev, sizeof(struct stm32_pwr_data), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - platform_set_drvdata(pdev, priv); - priv->dev = dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, res); + priv->base = of_iomap(np, 0); if (IS_ERR(priv->base)) { - dev_err(dev, "%s: Unable to map IO memory\n", __func__); - return PTR_ERR(priv->base); + pr_err("%s: Unable to map IO memory\n", __func__); + ret = PTR_ERR(priv->base); + goto out_free; } /* Disable all wake-up pins */ @@ -236,52 +233,38 @@ static int stm32_pwr_probe(struct platform_device *pdev) priv->domain = irq_domain_add_linear(np, NB_WAKEUPPINS, &stm32_pwr_irq_domain_ops, priv); if (!priv->domain) { - dev_err(dev, "%s: Unable to add irq domain!\n", __func__); - goto out; + pr_err("%s: Unable to add irq domain!\n", __func__); + ret = -ENOMEM; + goto out_unmap; } - ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "failed to get PWR IRQ\n"); - goto err; + priv->irq = irq_of_parse_and_map(np, 0); + if (priv->irq < 0) { + pr_err("failed to get PWR IRQ\n"); + ret = priv->irq; + goto out_domain; } - priv->irq = ret; irq_set_chained_handler_and_data(priv->irq, stm32_pwr_handle_irq, priv); -out: + of_node_clear_flag(np, OF_POPULATED); + return 0; -err: + +out_domain: irq_domain_remove(priv->domain); +out_unmap: + iounmap(priv->base); +out_free: + kfree(priv); return ret; } -static int stm32_pwr_remove(struct platform_device *pdev) +static int __init stm32_pwr_of_init(struct device_node *np, + struct device_node *parent) { - struct stm32_pwr_data *priv = platform_get_drvdata(pdev); - - irq_domain_remove(priv->domain); - return 0; + return stm32_pwr_init(np, parent); } -static const struct of_device_id stm32_pwr_match[] = { - { .compatible = "st,stm32mp1-pwr" }, - {}, -}; - -static struct platform_driver stm32_pwr_driver = { - .probe = stm32_pwr_probe, - .remove = stm32_pwr_remove, - .driver = { - .name = "stm32-pwr", - .owner = THIS_MODULE, - .of_match_table = stm32_pwr_match, - }, -}; - -static int __init stm32_pwr_init(void) -{ - return platform_driver_register(&stm32_pwr_driver); -} -arch_initcall(stm32_pwr_init); +IRQCHIP_DECLARE(stm32mp1_pwr_irq, "st,stm32mp1-pwr", stm32_pwr_of_init); diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c index 5bf6328..648315d 100644 --- a/drivers/mfd/stpmic1.c +++ b/drivers/mfd/stpmic1.c @@ -268,13 +268,8 @@ static int stpmic1_probe(struct i2c_client *i2c, return ddata->irq; } - ddata->irq_wake = of_irq_get(np, STPMIC1_WAKEUP_IRQ); - if (ddata->irq_wake > 0) { + if (of_property_read_bool(np, "wakeup-source")) device_init_wakeup(dev, true); - ret = dev_pm_set_dedicated_wake_irq(dev, ddata->irq_wake); - if (ret) - dev_warn(dev, "failed to set up wakeup irq"); - } if (!of_property_read_u32(np, "st,main-control-register", ®)) { ret = regmap_update_bits(ddata->regmap, @@ -371,8 +366,8 @@ static int stpmic1_suspend(struct device *dev) struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); disable_irq(pmic_dev->irq); - if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev)) - enable_irq_wake(pmic_dev->irq_wake); + if (device_may_wakeup(dev)) + enable_irq_wake(pmic_dev->irq); return 0; } @@ -387,9 +382,10 @@ static int stpmic1_resume(struct device *dev) if (ret) return ret; + if (device_may_wakeup(dev)) + disable_irq_wake(pmic_dev->irq); + enable_irq(pmic_dev->irq); - if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev)) - disable_irq_wake(pmic_dev->irq_wake); return 0; } diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index b6d05cd..a0ba4ff 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -12,6 +12,7 @@ * (at your option) any later version. */ +#include #include #include #include @@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = { static struct syscon *of_syscon_register(struct device_node *np) { + struct clk *clk; struct syscon *syscon; struct regmap *regmap; void __iomem *base; @@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np) goto err_regmap; } + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + /* clock is optional */ + if (ret != -ENOENT) + goto err_clk; + } else { + ret = regmap_mmio_attach_clk(regmap, clk); + if (ret) + goto err_attach; + } + syscon->regmap = regmap; syscon->np = np; @@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np) return syscon; +err_attach: + if (!IS_ERR(clk)) + clk_put(clk); +err_clk: + regmap_exit(regmap); err_regmap: iounmap(base); err_map: diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 22bd652..755863a 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -12,6 +12,7 @@ * */ +#include #include #include #include @@ -314,6 +315,20 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) if (pdata->ldo[1].enable < 0) pdata->ldo[1].enable = 0; + pdata->mclk1 = devm_clk_get(wm8994->dev, "MCLK1"); + if (IS_ERR(pdata->mclk1)) { + if (PTR_ERR(pdata->mclk1) != -ENOENT) + return PTR_ERR(pdata->mclk1); + pdata->mclk1 = NULL; + } + + pdata->mclk2 = devm_clk_get(wm8994->dev, "MCLK2"); + if (IS_ERR(pdata->mclk2)) { + if (PTR_ERR(pdata->mclk2) != -ENOENT) + return PTR_ERR(pdata->mclk2); + pdata->mclk2 = NULL; + } + return 0; } #else diff --git a/include/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h index 4abe5f1..fa3f99f 100644 --- a/include/linux/mfd/stpmic1.h +++ b/include/linux/mfd/stpmic1.h @@ -206,7 +206,6 @@ struct stpmic1 { struct device *dev; struct regmap *regmap; int irq; - int irq_wake; struct regmap_irq_chip_data *irq_data; }; -- 2.7.4