meta-st-stm32mp/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch

717 lines
20 KiB
Diff

From f811efe3cbe842a78d98740c0a0a8e1b7c0181b0 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Fri, 10 Apr 2020 14:45:15 +0200
Subject: [PATCH 13/23] ARM-stm32mp1-r1-MFD
---
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 1 +
drivers/mfd/stm32-pwr.c | 400 +++++++++++++++++++++++++++++++
drivers/mfd/stm32-timers.c | 36 ++-
drivers/mfd/stmfx.c | 22 +-
drivers/mfd/stpmic1.c | 6 +
drivers/mfd/wm8994-core.c | 21 ++
include/linux/mfd/stm32-timers.h | 12 +-
include/linux/mfd/stmfx.h | 1 +
include/linux/mfd/wm8994/pdata.h | 6 +
10 files changed, 494 insertions(+), 21 deletions(-)
create mode 100644 drivers/mfd/stm32-pwr.c
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 43169f25d..48ef1822a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1955,6 +1955,16 @@ config MFD_STPMIC1
To compile this driver as a module, choose M here: the
module will be called stpmic1.
+config MFD_STM32MP1_PWR
+ bool "STM32MP1 wake-up pins"
+ depends on MACH_STM32MP157
+ default y
+ help
+ Select this option to enable STM32 PWR Wake-up pins driver.
+
+ This driver provides interruptions that can be used to wake-up from
+ suspend.
+
config MFD_STMFX
tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c1067ea46..11acfa1bf 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -249,6 +249,7 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
+obj-$(CONFIG_MFD_STM32MP1_PWR) += stm32-pwr.o
obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c
new file mode 100644
index 000000000..48ca8b474
--- /dev/null
+++ b/drivers/mfd/stm32-pwr.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/gpio.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <asm/exception.h>
+
+#define NB_WAKEUPPINS 6
+
+#define STM32_SVC_PWR 0x82001001
+#define STM32_WRITE 0x1
+#define STM32_SET_BITS 0x2
+#define STM32_CLEAR_BITS 0x3
+
+#define PWR_WKUP_OFFSET 0x20
+// PWR Registers
+#define WKUPCR 0x0
+#define WKUPFR 0x4
+#define MPUWKUPENR 0x8
+
+#define WKUP_FLAGS_MASK GENMASK(5, 0)
+
+// WKUPCR bits definition
+#define WKUP_EDGE_SHIFT 8
+#define WKUP_PULL_SHIFT 16
+#define WKUP_PULL_MASK GENMASK(1, 0)
+
+enum wkup_pull_setting {
+ WKUP_NO_PULL = 0,
+ WKUP_PULL_UP,
+ WKUP_PULL_DOWN,
+ WKUP_PULL_RESERVED
+};
+
+#define SMC(class, op, offset, val) do { \
+ struct arm_smccc_res res; \
+ arm_smccc_smc(class, op, PWR_WKUP_OFFSET + (offset), val, \
+ 0, 0, 0, 0, &res); \
+} while (0) \
+
+struct stm32_pwr_data {
+ struct device *dev;
+ void __iomem *base; /* IO Memory base address */
+ struct irq_domain *domain; /* Domain for this controller */
+ int irq; /* Parent interrupt */
+ u32 masked; /* IRQ is masked */
+ u32 wake; /* IRQ is wake on */
+ u32 pending; /* IRQ has been received while wake on*/
+ struct gpio_desc *gpio[NB_WAKEUPPINS];
+};
+
+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);
+ SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, BIT(d->hwirq));
+}
+
+static void stm32_pwr_irq_set_enable(struct irq_data *d)
+{
+ struct stm32_pwr_data *priv = d->domain->host_data;
+
+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ if (!(priv->masked & BIT(d->hwirq)) || (priv->wake & BIT(d->hwirq)))
+ SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq));
+ else
+ SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, 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);
+ priv->masked |= BIT(d->hwirq);
+ stm32_pwr_irq_set_enable(d);
+}
+
+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);
+ priv->masked &= ~BIT(d->hwirq);
+ stm32_pwr_irq_set_enable(d);
+}
+
+static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct stm32_pwr_data *priv = d->domain->host_data;
+ struct irq_data *parent = irq_get_irq_data(priv->irq);
+
+ dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on);
+ if (on) {
+ priv->wake |= BIT(d->hwirq);
+ } else {
+ priv->wake &= ~BIT(d->hwirq);
+ priv->pending &= ~BIT(d->hwirq);
+ }
+ stm32_pwr_irq_set_enable(d);
+
+ if (parent->chip && parent->chip->irq_set_wake)
+ return parent->chip->irq_set_wake(parent, on);
+
+ return 0;
+}
+
+static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct stm32_pwr_data *priv = d->domain->host_data;
+ int pin_id = d->hwirq;
+ u32 wkupcr;
+ int en;
+
+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+
+ en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id);
+ /* reference manual request to disable the wakeup pin while
+ * changing the edge detection setting
+ */
+ if (en)
+ stm32_pwr_irq_mask(d);
+
+ wkupcr = readl_relaxed(priv->base + WKUPCR);
+ switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+ case IRQF_TRIGGER_FALLING:
+ wkupcr |= (1 << (WKUP_EDGE_SHIFT + pin_id));
+ break;
+ case IRQF_TRIGGER_RISING:
+ wkupcr &= ~(1 << (WKUP_EDGE_SHIFT + pin_id));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr);
+
+ if (en)
+ stm32_pwr_irq_unmask(d);
+
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+static int stm32_pwr_set_affinity_parent(struct irq_data *data,
+ const struct cpumask *dest, bool force)
+{
+ struct stm32_pwr_data *priv = data->domain->host_data;
+ struct irq_data *parent = irq_get_irq_data(priv->irq);
+
+ if (parent->chip && parent->chip->irq_set_affinity)
+ return parent->chip->irq_set_affinity(parent, dest, force);
+
+ return IRQ_SET_MASK_OK_DONE;
+}
+#endif
+
+static int stm32_pwr_irq_request_resources(struct irq_data *d)
+{
+ struct stm32_pwr_data *priv = d->domain->host_data;
+ struct gpio_desc *gpio;
+ int ret;
+
+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ gpio = gpiod_get_index(priv->dev, "wakeup", d->hwirq, GPIOD_IN);
+ if (IS_ERR(gpio)) {
+ ret = PTR_ERR(gpio);
+ dev_err(priv->dev, "Failed to get wakeup gpio: %d", ret);
+ return ret;
+ }
+ priv->gpio[d->hwirq] = gpio;
+ return 0;
+}
+
+static void stm32_pwr_irq_release_resources(struct irq_data *d)
+{
+ struct stm32_pwr_data *priv = d->domain->host_data;
+
+ dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ gpiod_put(priv->gpio[d->hwirq]);
+}
+
+static struct irq_chip stm32_pwr_irq_chip = {
+ .name = "stm32-pwr-irq",
+ .irq_ack = stm32_pwr_irq_ack,
+ .irq_mask = stm32_pwr_irq_mask,
+ .irq_unmask = stm32_pwr_irq_unmask,
+ .irq_set_type = stm32_pwr_irq_set_type,
+ .irq_set_wake = stm32_pwr_irq_set_wake,
+ .irq_request_resources = stm32_pwr_irq_request_resources,
+ .irq_release_resources = stm32_pwr_irq_release_resources,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = stm32_pwr_set_affinity_parent,
+#endif
+};
+
+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);
+
+ if (config >= WKUP_PULL_RESERVED) {
+ 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;
+}
+
+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)
+{
+ if (WARN_ON(intsize < 3)) {
+ pr_err("%s: bad irq config parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1] & (IRQ_TYPE_SENSE_MASK);
+
+ 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 = {
+ .alloc = stm32_pwr_alloc,
+ .xlate = stm32_pwr_xlate,
+ .free = irq_domain_free_irqs_common,
+};
+
+/*
+ * Handler for the cascaded IRQ.
+ */
+static void stm32_pwr_handle_irq(struct irq_desc *desc)
+{
+ struct stm32_pwr_data *priv = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 wkupfr, wkupenr, i;
+
+ chained_irq_enter(chip, 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))) {
+ struct irq_desc *d;
+
+ d = irq_to_desc(irq_find_mapping(priv->domain, i));
+
+ if (priv->wake & BIT(i)) {
+ dev_dbg(priv->dev,
+ "irq %d while wake enabled\n", i);
+ priv->pending |= BIT(i);
+ }
+
+ dev_dbg(priv->dev, "handle wkup irq:%d\n", i);
+ handle_edge_irq(d);
+ }
+ }
+ chained_irq_exit(chip, desc);
+}
+
+static int __maybe_unused stm32_pwr_suspend(struct device *dev)
+{
+ struct stm32_pwr_data *priv = dev_get_drvdata(dev);
+
+ pr_debug("suspend");
+ if (priv->pending != 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static const struct dev_pm_ops stm32_pwr_pm = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pwr_suspend, NULL)
+};
+
+static int stm32_pwr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_pwr_data *priv;
+ struct device_node *np = dev->of_node;
+ struct resource *res;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base)) {
+ dev_err(dev, "Unable to map registers\n");
+ return PTR_ERR(priv->base);
+ }
+
+ /* Disable all wake-up pins */
+ SMC(STM32_SVC_PWR, STM32_WRITE, MPUWKUPENR, 0);
+ /* Clear all interrupts flags */
+ SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, WKUP_FLAGS_MASK);
+
+ 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__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = irq_of_parse_and_map(np, 0);
+ if (ret < 0) {
+ dev_err(dev, "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);
+
+ of_node_clear_flag(np, OF_POPULATED);
+
+ return 0;
+
+out_domain:
+ irq_domain_remove(priv->domain);
+out:
+ return ret;
+}
+
+static int stm32_pwr_remove(struct platform_device *pdev)
+{
+ struct stm32_pwr_data *priv = dev_get_drvdata(&pdev->dev);
+
+ irq_domain_remove(priv->domain);
+ return 0;
+}
+
+static const struct of_device_id stm32_pwr_ids[] = {
+ { .compatible = "st,stm32mp1-pwr", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_pwr_ids);
+
+static struct platform_driver stm32_pwr_driver = {
+ .probe = stm32_pwr_probe,
+ .remove = stm32_pwr_remove,
+ .driver = {
+ .name = "stm32_pwr",
+ .of_match_table = stm32_pwr_ids,
+ .pm = &stm32_pwr_pm,
+ },
+};
+
+static int __init stm32_pwr_init(void)
+{
+ return platform_driver_register(&stm32_pwr_driver);
+}
+
+static void __exit stm32_pwr_exit(void)
+{
+ return platform_driver_unregister(&stm32_pwr_driver);
+}
+
+arch_initcall(stm32_pwr_init);
+module_exit(stm32_pwr_exit);
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index efcd4b980..65a160a26 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -167,26 +167,36 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
regmap_write(ddata->regmap, TIM_ARR, 0x0);
}
-static void stm32_timers_dma_probe(struct device *dev,
- struct stm32_timers *ddata)
+static int stm32_timers_dma_probe(struct device *dev,
+ struct stm32_timers *ddata)
{
int i;
+ int ret = 0;
char name[4];
init_completion(&ddata->dma.completion);
mutex_init(&ddata->dma.lock);
- /* Optional DMA support: get valid DMA channel(s) or NULL */
+ /* Optional DMA support but report if an existing one fails */
for (i = STM32_TIMERS_DMA_CH1; i <= STM32_TIMERS_DMA_CH4; i++) {
snprintf(name, ARRAY_SIZE(name), "ch%1d", i + 1);
- ddata->dma.chans[i] = dma_request_slave_channel(dev, name);
+ ddata->dma.chans[i] = dma_request_chan(dev, name);
}
- ddata->dma.chans[STM32_TIMERS_DMA_UP] =
- dma_request_slave_channel(dev, "up");
- ddata->dma.chans[STM32_TIMERS_DMA_TRIG] =
- dma_request_slave_channel(dev, "trig");
- ddata->dma.chans[STM32_TIMERS_DMA_COM] =
- dma_request_slave_channel(dev, "com");
+ ddata->dma.chans[STM32_TIMERS_DMA_UP] = dma_request_chan(dev, "up");
+ ddata->dma.chans[STM32_TIMERS_DMA_TRIG] = dma_request_chan(dev, "trig");
+ ddata->dma.chans[STM32_TIMERS_DMA_COM] = dma_request_chan(dev, "com");
+
+ for (i = STM32_TIMERS_DMA_CH1; i < STM32_TIMERS_MAX_DMAS; i++) {
+ if (IS_ERR(ddata->dma.chans[i])) {
+ /* Save the first error code to return */
+ if (PTR_ERR(ddata->dma.chans[i]) != -ENODEV && !ret)
+ ret = PTR_ERR(ddata->dma.chans[i]);
+
+ ddata->dma.chans[i] = NULL;
+ }
+ }
+
+ return ret;
}
static void stm32_timers_dma_remove(struct device *dev,
@@ -230,7 +240,11 @@ static int stm32_timers_probe(struct platform_device *pdev)
stm32_timers_get_arr_size(ddata);
- stm32_timers_dma_probe(dev, ddata);
+ ret = stm32_timers_dma_probe(dev, ddata);
+ if (ret) {
+ stm32_timers_dma_remove(dev, ddata);
+ return ret;
+ }
platform_set_drvdata(pdev, ddata);
diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c
index 857991cb3..711979afd 100644
--- a/drivers/mfd/stmfx.c
+++ b/drivers/mfd/stmfx.c
@@ -287,14 +287,21 @@ static int stmfx_irq_init(struct i2c_client *client)
ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin);
if (ret)
- return ret;
+ goto irq_exit;
ret = devm_request_threaded_irq(stmfx->dev, client->irq,
NULL, stmfx_irq_handler,
irqtrigger | IRQF_ONESHOT,
"stmfx", stmfx);
if (ret)
- stmfx_irq_exit(client);
+ goto irq_exit;
+
+ stmfx->irq = client->irq;
+
+ return 0;
+
+irq_exit:
+ stmfx_irq_exit(client);
return ret;
}
@@ -481,6 +488,8 @@ static int stmfx_suspend(struct device *dev)
if (ret)
return ret;
+ disable_irq(stmfx->irq);
+
if (stmfx->vdd)
return regulator_disable(stmfx->vdd);
@@ -501,6 +510,13 @@ static int stmfx_resume(struct device *dev)
}
}
+ /* Reset STMFX - supply has been stopped during suspend */
+ ret = stmfx_chip_reset(stmfx);
+ if (ret) {
+ dev_err(stmfx->dev, "Failed to reset chip: %d\n", ret);
+ return ret;
+ }
+
ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL,
&stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl));
if (ret)
@@ -517,6 +533,8 @@ static int stmfx_resume(struct device *dev)
if (ret)
return ret;
+ enable_irq(stmfx->irq);
+
return 0;
}
#endif
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
index 7dfbe8906..766c3217f 100644
--- a/drivers/mfd/stpmic1.c
+++ b/drivers/mfd/stpmic1.c
@@ -170,6 +170,9 @@ static int stpmic1_suspend(struct device *dev)
disable_irq(pmic_dev->irq);
+ if (device_may_wakeup(dev))
+ enable_irq_wake(pmic_dev->irq);
+
return 0;
}
@@ -183,6 +186,9 @@ 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);
return 0;
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 1e9fe7d92..b110c8ac1 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -185,6 +186,12 @@ static int wm8994_resume(struct device *dev)
if (!wm8994->suspended)
return 0;
+ /*
+ * LDO1/2 minimum cycle time is 36ms according to codec specification
+ * Wait before enabling regulator to make sure we fit this requirement
+ */
+ msleep(40);
+
ret = regulator_bulk_enable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
@@ -300,6 +307,20 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994)
pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd");
+
+ 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/stm32-timers.h b/include/linux/mfd/stm32-timers.h
index 067d14655..f8db83aed 100644
--- a/include/linux/mfd/stm32-timers.h
+++ b/include/linux/mfd/stm32-timers.h
@@ -70,14 +70,11 @@
#define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */
#define TIM_CCER_CC4P BIT(13) /* Capt/Comp 4 Polarity */
#define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12))
-#define TIM_BDTR_BKE BIT(12) /* Break input enable */
-#define TIM_BDTR_BKP BIT(13) /* Break input polarity */
+#define TIM_BDTR_BKE(x) BIT(12 + (x) * 12) /* Break input enable */
+#define TIM_BDTR_BKP(x) BIT(13 + (x) * 12) /* Break input polarity */
#define TIM_BDTR_AOE BIT(14) /* Automatic Output Enable */
#define TIM_BDTR_MOE BIT(15) /* Main Output Enable */
-#define TIM_BDTR_BKF (BIT(16) | BIT(17) | BIT(18) | BIT(19))
-#define TIM_BDTR_BK2F (BIT(20) | BIT(21) | BIT(22) | BIT(23))
-#define TIM_BDTR_BK2E BIT(24) /* Break 2 input enable */
-#define TIM_BDTR_BK2P BIT(25) /* Break 2 input polarity */
+#define TIM_BDTR_BKF(x) (0xf << (16 + (x) * 4))
#define TIM_DCR_DBA GENMASK(4, 0) /* DMA base addr */
#define TIM_DCR_DBL GENMASK(12, 8) /* DMA burst len */
@@ -87,8 +84,7 @@
#define TIM_CR2_MMS2_SHIFT 20
#define TIM_SMCR_TS_SHIFT 4
#define TIM_BDTR_BKF_MASK 0xF
-#define TIM_BDTR_BKF_SHIFT 16
-#define TIM_BDTR_BK2F_SHIFT 20
+#define TIM_BDTR_BKF_SHIFT(x) (16 + (x) * 4)
enum stm32_timers_dmas {
STM32_TIMERS_DMA_CH1,
diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h
index 3c6798367..744dce639 100644
--- a/include/linux/mfd/stmfx.h
+++ b/include/linux/mfd/stmfx.h
@@ -109,6 +109,7 @@ struct stmfx {
struct device *dev;
struct regmap *map;
struct regulator *vdd;
+ int irq;
struct irq_domain *irq_domain;
struct mutex lock; /* IRQ bus lock */
u8 irq_src;
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index 81e7dcbd9..addb2fede 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -231,6 +231,12 @@ struct wm8994_pdata {
* GPIO for the IRQ pin if host only supports edge triggering
*/
int irq_gpio;
+
+ /* MCLK1 clock provider */
+ struct clk *mclk1;
+
+ /* MCLK2 clock provider */
+ struct clk *mclk2;
};
#endif
--
2.17.1