Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1698638 > unrolled thread
| Started by | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| First post | 2017-07-28 11:50 +0200 |
| Last post | 2017-07-28 12:00 +0200 |
| Articles | 7 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v4 00/17] Add support for Cirrus Logic CS47L35/L85/L90/L91 codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 11:50 +0200
[PATCH v4 03/17] mfd: madera: Add common support for Cirrus Logic Madera codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 11:50 +0200
[PATCH v4 02/17] mfd: madera: Add DT bindings for Cirrus Logic Madera codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 12:00 +0200
[PATCH v4 09/17] irqchip: Add driver for Cirrus Logic Madera codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 12:00 +0200
[PATCH v4 12/17] gpio: madera: Support Cirrus Logic Madera class codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 12:00 +0200
[PATCH v4 07/17] regulator: arizona-micsupp: Add support for Cirrus Logic Madera codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 12:00 +0200
[PATCH v4 10/17] pinctrl: madera: Add DT bindings for Cirrus Logic Madera codecs Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - 2017-07-28 12:00 +0200
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 11:50 +0200 |
| Subject | [PATCH v4 00/17] Add support for Cirrus Logic CS47L35/L85/L90/L91 codecs |
| Message-ID | <u8a49-20x-3@gated-at.bofh.it> |
The Cirrus Logic CS47L35, CS47L85, CS47L90/91 codecs are complex audio SoC devices. In addition to the core audio capability they have onboard GPIO, regulators, DSPs and interrupt controller and a large register map space accessed over SPI or I2C. This family of codecs is based around common IP blocks and they are managed by a set of common drivers referred to as "Madera". Summary of changes since V3: - Manually stripped register definitions we're not using right now from registers.h to reduce the size and included some explanation in the commit message for why we do it the way we do - Fixed review comments on MFD code - Fixed Kconfig dependency error on pinctrl (missing dependency in MFD) - minor bugfixes to routing in CS47L85 and CS47L90 codec drivers Richard Fitzgerald (17): mfd: madera: Add register definitions for Cirrus Logic Madera codecs mfd: madera: Add DT bindings for Cirrus Logic Madera codecs mfd: madera: Add common support for Cirrus Logic Madera codecs mfd: madera: Register map tables for Cirrus Logic CS47L35 mfd: madera: Register map tables for Cirrus Logic CS47L85 mfd: madera: Register map tables for Cirrus Logic CS47L90/91 regulator: arizona-micsupp: Add support for Cirrus Logic Madera codecs regulator: arizona-ldo1: Add support for Cirrus Logic Madera codecs irqchip: Add driver for Cirrus Logic Madera codecs pinctrl: madera: Add DT bindings for Cirrus Logic Madera codecs pinctrl: madera: Add driver for Cirrus Logic Madera codecs gpio: madera: Support Cirrus Logic Madera class codecs ASoC: madera: Add DT bindings for Cirrus Logic Madera codecs ASoC: madera: Add common support for Cirrus Logic Madera codecs ASoC: cs47l35: Add codec driver for Cirrus Logic CS47L35 ASoC: cs47l85: Add codec driver for Cirrus Logic CS47L85 ASoC: cs47l90: Add codec driver for Cirrus Logic CS47L90 Documentation/devicetree/bindings/mfd/madera.txt | 102 + .../bindings/pinctrl/cirrus,madera-pinctrl.txt | 99 + .../bindings/regulator/arizona-regulator.txt | 3 +- Documentation/devicetree/bindings/sound/madera.txt | 67 + MAINTAINERS | 23 + drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-madera.c | 196 + drivers/irqchip/Kconfig | 3 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-madera.c | 301 ++ drivers/mfd/Kconfig | 48 + drivers/mfd/Makefile | 13 + drivers/mfd/cs47l35-tables.c | 1610 +++++++ drivers/mfd/cs47l85-tables.c | 3010 +++++++++++++ drivers/mfd/cs47l90-tables.c | 2675 ++++++++++++ drivers/mfd/madera-core.c | 617 +++ drivers/mfd/madera-i2c.c | 135 + drivers/mfd/madera-spi.c | 135 + drivers/mfd/madera.h | 54 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/cirrus/Kconfig | 15 + drivers/pinctrl/cirrus/Makefile | 11 + drivers/pinctrl/cirrus/pinctrl-cs47l35.c | 46 + drivers/pinctrl/cirrus/pinctrl-cs47l85.c | 60 + drivers/pinctrl/cirrus/pinctrl-cs47l90.c | 58 + drivers/pinctrl/cirrus/pinctrl-madera.c | 1074 +++++ drivers/pinctrl/cirrus/pinctrl-madera.h | 40 + drivers/regulator/Kconfig | 15 +- drivers/regulator/arizona-ldo1.c | 82 +- drivers/regulator/arizona-micsupp.c | 71 +- include/dt-bindings/sound/madera.h | 27 + include/linux/irqchip/irq-madera-pdata.h | 23 + include/linux/irqchip/irq-madera.h | 96 + include/linux/mfd/madera/core.h | 179 + include/linux/mfd/madera/pdata.h | 61 + include/linux/mfd/madera/registers.h | 3987 ++++++++++++++++++ include/sound/madera-pdata.h | 61 + sound/soc/codecs/Kconfig | 23 + sound/soc/codecs/Makefile | 8 + sound/soc/codecs/cs47l35.c | 1747 ++++++++ sound/soc/codecs/cs47l85.c | 2722 ++++++++++++ sound/soc/codecs/cs47l90.c | 2661 ++++++++++++ sound/soc/codecs/madera.c | 4438 ++++++++++++++++++++ sound/soc/codecs/madera.h | 470 +++ 46 files changed, 27066 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/madera.txt create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt create mode 100644 Documentation/devicetree/bindings/sound/madera.txt create mode 100644 drivers/gpio/gpio-madera.c create mode 100644 drivers/irqchip/irq-madera.c create mode 100644 drivers/mfd/cs47l35-tables.c create mode 100644 drivers/mfd/cs47l85-tables.c create mode 100644 drivers/mfd/cs47l90-tables.c create mode 100644 drivers/mfd/madera-core.c create mode 100644 drivers/mfd/madera-i2c.c create mode 100644 drivers/mfd/madera-spi.c create mode 100644 drivers/mfd/madera.h create mode 100644 drivers/pinctrl/cirrus/Kconfig create mode 100644 drivers/pinctrl/cirrus/Makefile create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs47l35.c create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs47l85.c create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs47l90.c create mode 100644 drivers/pinctrl/cirrus/pinctrl-madera.c create mode 100644 drivers/pinctrl/cirrus/pinctrl-madera.h create mode 100644 include/dt-bindings/sound/madera.h create mode 100644 include/linux/irqchip/irq-madera-pdata.h create mode 100644 include/linux/irqchip/irq-madera.h create mode 100644 include/linux/mfd/madera/core.h create mode 100644 include/linux/mfd/madera/pdata.h create mode 100644 include/linux/mfd/madera/registers.h create mode 100644 include/sound/madera-pdata.h create mode 100644 sound/soc/codecs/cs47l35.c create mode 100644 sound/soc/codecs/cs47l85.c create mode 100644 sound/soc/codecs/cs47l90.c create mode 100644 sound/soc/codecs/madera.c create mode 100644 sound/soc/codecs/madera.h -- 1.9.1
[toc] | [next] | [standalone]
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 11:50 +0200 |
| Subject | [PATCH v4 03/17] mfd: madera: Add common support for Cirrus Logic Madera codecs |
| Message-ID | <u8a4d-20x-39@gated-at.bofh.it> |
| In reply to | #1698638 |
This adds the generic core support for Cirrus Logic "Madera" class codecs.
These are complex audio codec SoCs with a variety of digital and analogue
I/O, onboard audio processing and DSPs, and other features.
These codecs are all based off a common set of hardware IP so can be
supported by a core of common code (with a few minor device-to-device
variations).
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Nikesh Oswal <Nikesh.Oswal@wolfsonmicro.com>
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
---
Changes since V3:
- Fixed missing Kconfig dependency on PINCTRL
- commented purpose of madera_name_from_type(), call it earlier
in probe and store the string in a member of struct madera
- removed the madera_get_num_micbias and madera_get_num_childbias
exported functions and introduced static madera_set_micbias_info
to init this information in members of struct madera
- adjusted the commenting on the switch that adds the LDO1 child driver
- squashed the two switches on hardware ID into one (we used to re-read
the HWID after reset hence the second switch on it but as we don't do
that now the two switches can be combined)
- pre-init ret to remove the else ret = 0 in madera_get_reset_gpio
Changes not made to V3 review comments:
- left the dev_dbg messages in runtime_suspend and runtime_resume,
they are only _dbg and they've been useful in the past for debugging
MAINTAINERS | 3 +
drivers/mfd/Kconfig | 27 ++
drivers/mfd/Makefile | 4 +
drivers/mfd/madera-core.c | 611 +++++++++++++++++++++++++++++++++++++++
drivers/mfd/madera-i2c.c | 135 +++++++++
drivers/mfd/madera-spi.c | 135 +++++++++
drivers/mfd/madera.h | 54 ++++
include/linux/mfd/madera/core.h | 179 ++++++++++++
include/linux/mfd/madera/pdata.h | 61 ++++
9 files changed, 1209 insertions(+)
create mode 100644 drivers/mfd/madera-core.c
create mode 100644 drivers/mfd/madera-i2c.c
create mode 100644 drivers/mfd/madera-spi.c
create mode 100644 drivers/mfd/madera.h
create mode 100644 include/linux/mfd/madera/core.h
create mode 100644 include/linux/mfd/madera/pdata.h
diff --git a/MAINTAINERS b/MAINTAINERS
index f70d218..f335b2a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3376,7 +3376,10 @@ L: patches@opensource.wolfsonmicro.com
T: git https://github.com/CirrusLogic/linux-drivers.git
W: https://github.com/CirrusLogic/linux-drivers/wiki
S: Supported
+F: Documentation/devicetree/bindings/mfd/madera.txt
F: include/linux/mfd/madera/*
+F: drivers/mfd/madera*
+F: drivers/mfd/cs47l*
CLEANCACHE API
M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 94ad2c1..9ca7174 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -208,6 +208,33 @@ config MFD_CROS_EC_SPI
response time cannot be guaranteed, we support ignoring
'pre-amble' bytes before the response actually starts.
+config MFD_MADERA
+ bool
+ select MFD_CORE
+ select REGMAP
+ select REGMAP_IRQ
+ select MADERA_IRQ
+
+config MFD_MADERA_I2C
+ bool "Cirrus Logic Madera codecs with I2C"
+ select MFD_MADERA
+ select REGMAP_I2C
+ depends on I2C
+ depends on PINCTRL
+ help
+ Support for the Cirrus Logic Madera platform audio SoC
+ core functionality controlled via I2C.
+
+config MFD_MADERA_SPI
+ bool "Cirrus Logic Madera codecs with SPI"
+ select MFD_MADERA
+ select REGMAP_SPI
+ depends on SPI_MASTER
+ depends on PINCTRL
+ help
+ Support for the Cirrus Logic Madera platform audio SoC
+ core functionality controlled via SPI.
+
config MFD_ASIC3
bool "Compaq ASIC3"
depends on GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 080793b..71c658a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -73,6 +73,10 @@ obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o
obj-$(CONFIG_MFD_WM8994) += wm8994.o
+obj-$(CONFIG_MFD_MADERA) += madera-core.o
+obj-$(CONFIG_MFD_MADERA_I2C) += madera-i2c.o
+obj-$(CONFIG_MFD_MADERA_SPI) += madera-spi.o
+
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o
diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c
new file mode 100644
index 0000000..2d83a57
--- /dev/null
+++ b/drivers/mfd/madera-core.c
@@ -0,0 +1,611 @@
+/*
+ * Core MFD support for Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * 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 <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/registers.h>
+
+#include "madera.h"
+
+#define CS47L35_SILICON_ID 0x6360
+#define CS47L85_SILICON_ID 0x6338
+#define CS47L90_SILICON_ID 0x6364
+
+#define MADERA_32KZ_MCLK2 1
+
+static const char * const madera_core_supplies[] = {
+ "AVDD",
+ "DBVDD1",
+};
+
+static const struct mfd_cell madera_ldo1_devs[] = {
+ { .name = "madera-ldo1" },
+};
+
+static const char * const cs47l35_supplies[] = {
+ "MICVDD",
+ "DBVDD2",
+ "CPVDD1",
+ "CPVDD2",
+ "SPKVDD",
+};
+
+static const struct mfd_cell cs47l35_devs[] = {
+ { .name = "madera-pinctrl", },
+ { .name = "madera-irq", },
+ { .name = "madera-micsupp", },
+ { .name = "madera-gpio", },
+ { .name = "madera-extcon", },
+ {
+ .name = "cs47l35-codec",
+ .parent_supplies = cs47l35_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l35_supplies),
+ },
+};
+
+static const char * const cs47l85_supplies[] = {
+ "MICVDD",
+ "DBVDD2",
+ "DBVDD3",
+ "DBVDD4",
+ "CPVDD1",
+ "CPVDD2",
+ "SPKVDDL",
+ "SPKVDDR",
+};
+
+static const struct mfd_cell cs47l85_devs[] = {
+ { .name = "madera-pinctrl", },
+ { .name = "madera-irq", },
+ { .name = "madera-micsupp" },
+ { .name = "madera-gpio", },
+ { .name = "madera-extcon", },
+ {
+ .name = "cs47l85-codec",
+ .parent_supplies = cs47l85_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l85_supplies),
+ },
+};
+
+static const char * const cs47l90_supplies[] = {
+ "MICVDD",
+ "DBVDD2",
+ "DBVDD3",
+ "DBVDD4",
+ "CPVDD1",
+ "CPVDD2",
+};
+
+static const struct mfd_cell cs47l90_devs[] = {
+ { .name = "madera-pinctrl", },
+ { .name = "madera-irq", },
+ { .name = "madera-micsupp", },
+ { .name = "madera-gpio", },
+ { .name = "madera-extcon", },
+ {
+ .name = "cs47l90-codec",
+ .parent_supplies = cs47l90_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l90_supplies),
+ },
+};
+
+/* Used by madera-i2c and madera-spi drivers */
+const char *madera_name_from_type(enum madera_type type)
+{
+ switch (type) {
+ case CS47L35:
+ return "CS47L35";
+ case CS47L85:
+ return "CS47L85";
+ case CS47L90:
+ return "CS47L90";
+ case CS47L91:
+ return "CS47L91";
+ case WM1840:
+ return "WM1840";
+ default:
+ return "Unknown";
+ }
+}
+EXPORT_SYMBOL_GPL(madera_name_from_type);
+
+#define MADERA_BOOT_POLL_MAX_INTERVAL_US 5000
+#define MADERA_BOOT_POLL_TIMEOUT_US 25000
+
+static int madera_wait_for_boot(struct madera *madera)
+{
+ unsigned int val;
+ int ret;
+
+ /*
+ * We can't use an interrupt as we need to runtime resume to do so,
+ * so we poll the status bit. This won't race with the interrupt
+ * handler because it will be blocked on runtime resume.
+ */
+ ret = regmap_read_poll_timeout(madera->regmap,
+ MADERA_IRQ1_RAW_STATUS_1,
+ val,
+ (val & MADERA_BOOT_DONE_STS1),
+ MADERA_BOOT_POLL_MAX_INTERVAL_US,
+ MADERA_BOOT_POLL_TIMEOUT_US);
+
+ if (ret)
+ dev_err(madera->dev, "Polling BOOT_DONE_STS failed: %d\n", ret);
+
+ /*
+ * BOOT_DONE defaults to unmasked on boot so we must ack it.
+ * Do this unconditionally to avoid interrupt storms
+ */
+ regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1,
+ MADERA_BOOT_DONE_EINT1);
+
+ pm_runtime_mark_last_busy(madera->dev);
+
+ return ret;
+}
+
+static int madera_soft_reset(struct madera *madera)
+{
+ int ret;
+
+ ret = regmap_write(madera->regmap, MADERA_SOFTWARE_RESET, 0);
+ if (ret != 0) {
+ dev_err(madera->dev, "Failed to soft reset device: %d\n", ret);
+ return ret;
+ }
+
+ /* Allow time for internal clocks to startup after reset */
+ usleep_range(1000, 2000);
+
+ return 0;
+}
+
+static void madera_enable_hard_reset(struct madera *madera)
+{
+ if (madera->reset_gpio)
+ gpiod_set_value_cansleep(madera->reset_gpio, 0);
+}
+
+static void madera_disable_hard_reset(struct madera *madera)
+{
+ if (madera->reset_gpio) {
+ gpiod_set_value_cansleep(madera->reset_gpio, 1);
+ usleep_range(1000, 2000);
+ }
+}
+
+#ifdef CONFIG_PM
+static int madera_runtime_resume(struct device *dev)
+{
+ struct madera *madera = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(dev, "Leaving sleep mode\n");
+
+ ret = regulator_enable(madera->dcvdd);
+ if (ret) {
+ dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
+ return ret;
+ }
+
+ regcache_cache_only(madera->regmap, false);
+ regcache_cache_only(madera->regmap_32bit, false);
+
+ ret = madera_wait_for_boot(madera);
+ if (ret)
+ goto err;
+
+ ret = regcache_sync(madera->regmap);
+ if (ret) {
+ dev_err(dev, "Failed to restore 16-bit register cache\n");
+ goto err;
+ }
+
+ ret = regcache_sync(madera->regmap_32bit);
+ if (ret) {
+ dev_err(dev, "Failed to restore 32-bit register cache\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regcache_cache_only(madera->regmap_32bit, true);
+ regcache_cache_only(madera->regmap, true);
+ regulator_disable(madera->dcvdd);
+
+ return ret;
+}
+
+static int madera_runtime_suspend(struct device *dev)
+{
+ struct madera *madera = dev_get_drvdata(dev);
+
+ dev_dbg(madera->dev, "Entering sleep mode\n");
+
+ regcache_cache_only(madera->regmap, true);
+ regcache_mark_dirty(madera->regmap);
+ regcache_cache_only(madera->regmap_32bit, true);
+ regcache_mark_dirty(madera->regmap_32bit);
+
+ regulator_disable(madera->dcvdd);
+
+ return 0;
+}
+#endif
+
+const struct dev_pm_ops madera_pm_ops = {
+ SET_RUNTIME_PM_OPS(madera_runtime_suspend,
+ madera_runtime_resume,
+ NULL)
+};
+EXPORT_SYMBOL_GPL(madera_pm_ops);
+
+#ifdef CONFIG_OF
+const struct of_device_id madera_of_match[] = {
+ { .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 },
+ { .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 },
+ { .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 },
+ { .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 },
+ { .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
+ {},
+};
+EXPORT_SYMBOL_GPL(madera_of_match);
+
+unsigned long madera_get_type_from_of(struct device *dev)
+{
+ const struct of_device_id *id = of_match_device(madera_of_match, dev);
+
+ if (id)
+ return (unsigned long)id->data;
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(madera_get_type_from_of);
+#endif
+
+static int madera_get_reset_gpio(struct madera *madera)
+{
+ int ret = 0;
+
+ /* We use 0 in pdata to indicate a GPIO has not been set */
+ if (dev_get_platdata(madera->dev) && (madera->pdata.reset > 0)) {
+ /* Start out with /RESET asserted */
+ ret = devm_gpio_request_one(madera->dev,
+ madera->pdata.reset,
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW,
+ "madera reset");
+ if (!ret)
+ madera->reset_gpio = gpio_to_desc(madera->pdata.reset);
+ } else {
+ madera->reset_gpio = devm_gpiod_get_optional(madera->dev,
+ "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(madera->reset_gpio))
+ ret = PTR_ERR(madera->reset_gpio);
+ }
+
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ if (ret) {
+ dev_err(madera->dev, "Failed to request /RESET: %d\n", ret);
+ return ret;
+ }
+
+ if (!madera->reset_gpio)
+ dev_warn(madera->dev,
+ "Running without reset GPIO is not recommended\n");
+
+ return 0;
+}
+
+static void madera_set_micbias_info(struct madera *madera)
+{
+ /*
+ * childbias is an array because future codecs can have different
+ * childbiases for each micbias
+ */
+ switch (madera->type) {
+ case CS47L35:
+ madera->num_micbias = 2;
+ madera->num_childbias[0] = 2;
+ madera->num_childbias[1] = 2;
+ return;
+ case CS47L85:
+ case WM1840:
+ madera->num_micbias = 4;
+ return;
+ case CS47L90:
+ case CS47L91:
+ madera->num_micbias = 2;
+ madera->num_childbias[0] = 4;
+ madera->num_childbias[1] = 4;
+ return;
+ default:
+ return;
+ }
+}
+
+int madera_dev_init(struct madera *madera)
+{
+ struct device *dev = madera->dev;
+ unsigned int hwid;
+ int (*patch_fn)(struct madera *) = NULL;
+ const struct mfd_cell *mfd_devs;
+ int n_devs = 0;
+ int i, ret;
+
+ dev_set_drvdata(madera->dev, madera);
+ BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier);
+ madera_set_micbias_info(madera);
+
+ if (dev_get_platdata(madera->dev)) {
+ memcpy(&madera->pdata, dev_get_platdata(madera->dev),
+ sizeof(madera->pdata));
+ }
+
+ ret = madera_get_reset_gpio(madera);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(madera->regmap, true);
+ regcache_cache_only(madera->regmap_32bit, true);
+
+ for (i = 0; i < ARRAY_SIZE(madera_core_supplies); i++)
+ madera->core_supplies[i].supply = madera_core_supplies[i];
+
+ madera->num_core_supplies = ARRAY_SIZE(madera_core_supplies);
+
+ /*
+ * On some codecs DCVDD could be supplied by the internal LDO1.
+ * For those we must add the LDO1 driver before requesting DCVDD
+ */
+ switch (madera->type) {
+ case CS47L35:
+ case CS47L90:
+ case CS47L91:
+ break;
+ case CS47L85:
+ case WM1840:
+ ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
+ madera_ldo1_devs,
+ ARRAY_SIZE(madera_ldo1_devs),
+ NULL, 0, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to add LDO1 child: %d\n", ret);
+ return ret;
+ }
+ break;
+ default:
+ /* no point continuing if the type is unknown */
+ dev_err(madera->dev, "Unknown device type %d\n", madera->type);
+ return -ENODEV;
+ }
+
+ ret = devm_regulator_bulk_get(dev, madera->num_core_supplies,
+ madera->core_supplies);
+ if (ret) {
+ dev_err(dev, "Failed to request core supplies: %d\n", ret);
+ goto err_devs;
+ }
+
+ /*
+ * Don't use devres here because the only device we have to get
+ * against is the MFD device and DCVDD will likely be supplied by
+ * one of its children. Meaning that the regulator will be
+ * destroyed by the time devres calls regulator put.
+ */
+ madera->dcvdd = regulator_get_exclusive(madera->dev, "DCVDD");
+ if (IS_ERR(madera->dcvdd)) {
+ ret = PTR_ERR(madera->dcvdd);
+ dev_err(dev, "Failed to request DCVDD: %d\n", ret);
+ goto err_devs;
+ }
+
+ ret = regulator_bulk_enable(madera->num_core_supplies,
+ madera->core_supplies);
+ if (ret) {
+ dev_err(dev, "Failed to enable core supplies: %d\n", ret);
+ goto err_dcvdd;
+ }
+
+ ret = regulator_enable(madera->dcvdd);
+ if (ret) {
+ dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
+ goto err_enable;
+ }
+
+ madera_disable_hard_reset(madera);
+
+ regcache_cache_only(madera->regmap, false);
+ regcache_cache_only(madera->regmap_32bit, false);
+
+ /*
+ * Verify that this is a chip we know about before we
+ * starting doing any writes to its registers
+ */
+ ret = regmap_read(madera->regmap, MADERA_SOFTWARE_RESET, &hwid);
+ if (ret) {
+ dev_err(dev, "Failed to read ID register: %d\n", ret);
+ goto err_reset;
+ }
+
+ switch (hwid) {
+ case CS47L35_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
+ switch (madera->type) {
+ case CS47L35:
+ patch_fn = cs47l35_patch;
+ mfd_devs = cs47l35_devs;
+ n_devs = ARRAY_SIZE(cs47l35_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case CS47L85_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L85)) {
+ switch (madera->type) {
+ case CS47L85:
+ case WM1840:
+ patch_fn = cs47l85_patch;
+ mfd_devs = cs47l85_devs;
+ n_devs = ARRAY_SIZE(cs47l85_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case CS47L90_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L90)) {
+ switch (madera->type) {
+ case CS47L90:
+ case CS47L91:
+ patch_fn = cs47l90_patch;
+ mfd_devs = cs47l90_devs;
+ n_devs = ARRAY_SIZE(cs47l90_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ dev_err(madera->dev, "Unknown device ID: %x\n", hwid);
+ ret = -EINVAL;
+ goto err_reset;
+ }
+
+ if (!n_devs) {
+ dev_err(madera->dev, "Device ID 0x%x not a %s\n", hwid,
+ madera->type_name);
+ ret = -ENODEV;
+ goto err_reset;
+ }
+
+ /*
+ * It looks like a device we support. If we don't have a hard reset
+ * we can now attempt a soft reset
+ */
+ if (!madera->reset_gpio) {
+ ret = madera_soft_reset(madera);
+ if (ret)
+ goto err_reset;
+ }
+
+ ret = madera_wait_for_boot(madera);
+ if (ret) {
+ dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
+ goto err_reset;
+ }
+
+ ret = regmap_read(madera->regmap, MADERA_HARDWARE_REVISION,
+ &madera->rev);
+ if (ret) {
+ dev_err(dev, "Failed to read revision register: %d\n", ret);
+ goto err_reset;
+ }
+ madera->rev &= MADERA_HW_REVISION_MASK;
+
+ dev_info(dev, "%s silicon revision %d\n", madera->type_name,
+ madera->rev);
+
+ /* Apply hardware patch */
+ if (patch_fn) {
+ ret = patch_fn(madera);
+ if (ret) {
+ dev_err(madera->dev, "Failed to apply patch %d\n", ret);
+ goto err_reset;
+ }
+ }
+
+ /* Init 32k clock sourced from MCLK2 */
+ ret = regmap_update_bits(madera->regmap,
+ MADERA_CLOCK_32K_1,
+ MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK,
+ MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2);
+ if (ret) {
+ dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret);
+ goto err_reset;
+ }
+
+ pm_runtime_set_active(madera->dev);
+ pm_runtime_enable(madera->dev);
+ pm_runtime_set_autosuspend_delay(madera->dev, 100);
+ pm_runtime_use_autosuspend(madera->dev);
+
+ ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
+ mfd_devs, n_devs,
+ NULL, 0, NULL);
+ if (ret) {
+ dev_err(madera->dev, "Failed to add subdevices: %d\n", ret);
+ goto err_pm_runtime;
+ }
+
+ return 0;
+
+err_pm_runtime:
+ pm_runtime_disable(madera->dev);
+err_reset:
+ madera_enable_hard_reset(madera);
+ regulator_disable(madera->dcvdd);
+err_enable:
+ regulator_bulk_disable(madera->num_core_supplies,
+ madera->core_supplies);
+err_dcvdd:
+ regulator_put(madera->dcvdd);
+err_devs:
+ mfd_remove_devices(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(madera_dev_init);
+
+int madera_dev_exit(struct madera *madera)
+{
+ /* Prevent any IRQs being serviced while we clean up */
+ disable_irq(madera->irq);
+
+ /*
+ * DCVDD could be supplied by a child node, we must disable it before
+ * removing the children, and prevent PM runtime from turning it back on
+ */
+ pm_runtime_disable(madera->dev);
+
+ regulator_disable(madera->dcvdd);
+ regulator_put(madera->dcvdd);
+
+ mfd_remove_devices(madera->dev);
+ madera_enable_hard_reset(madera);
+
+ regulator_bulk_disable(madera->num_core_supplies,
+ madera->core_supplies);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(madera_dev_exit);
diff --git a/drivers/mfd/madera-i2c.c b/drivers/mfd/madera-i2c.c
new file mode 100644
index 0000000..80c2304
--- /dev/null
+++ b/drivers/mfd/madera-i2c.c
@@ -0,0 +1,135 @@
+/*
+ * I2C bus interface to Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * 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 <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+
+#include <linux/mfd/madera/core.h>
+
+#include "madera.h"
+
+static int madera_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct madera *madera;
+ const struct regmap_config *regmap_16bit_config = NULL;
+ const struct regmap_config *regmap_32bit_config = NULL;
+ unsigned long type;
+ const char *name;
+ int ret;
+
+ if (i2c->dev.of_node)
+ type = madera_get_type_from_of(&i2c->dev);
+ else
+ type = id->driver_data;
+
+ switch (type) {
+ case CS47L35:
+ if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
+ regmap_16bit_config = &cs47l35_16bit_i2c_regmap;
+ regmap_32bit_config = &cs47l35_32bit_i2c_regmap;
+ }
+ break;
+ case CS47L85:
+ case WM1840:
+ if (IS_ENABLED(CONFIG_MFD_CS47L85)) {
+ regmap_16bit_config = &cs47l85_16bit_i2c_regmap;
+ regmap_32bit_config = &cs47l85_32bit_i2c_regmap;
+ }
+ break;
+ case CS47L90:
+ case CS47L91:
+ if (IS_ENABLED(CONFIG_MFD_CS47L90)) {
+ regmap_16bit_config = &cs47l90_16bit_i2c_regmap;
+ regmap_32bit_config = &cs47l90_32bit_i2c_regmap;
+ }
+ break;
+ default:
+ dev_err(&i2c->dev,
+ "Unknown Madera I2C device type %ld\n", type);
+ return -EINVAL;
+ }
+
+ name = madera_name_from_type(type);
+
+ if (!regmap_16bit_config) {
+ dev_err(&i2c->dev,
+ "Kernel does not include support for %s\n", name);
+ return -EINVAL;
+ }
+
+ madera = devm_kzalloc(&i2c->dev, sizeof(*madera), GFP_KERNEL);
+ if (!madera)
+ return -ENOMEM;
+
+
+ madera->regmap = devm_regmap_init_i2c(i2c, regmap_16bit_config);
+ if (IS_ERR(madera->regmap)) {
+ ret = PTR_ERR(madera->regmap);
+ dev_err(&i2c->dev,
+ "Failed to allocate 16-bit register map: %d\n", ret);
+ return ret;
+ }
+
+ madera->regmap_32bit = devm_regmap_init_i2c(i2c, regmap_32bit_config);
+ if (IS_ERR(madera->regmap_32bit)) {
+ ret = PTR_ERR(madera->regmap_32bit);
+ dev_err(&i2c->dev,
+ "Failed to allocate 32-bit register map: %d\n", ret);
+ return ret;
+ }
+
+ madera->type = type;
+ madera->type_name = name;
+ madera->dev = &i2c->dev;
+ madera->irq = i2c->irq;
+
+ return madera_dev_init(madera);
+}
+
+static int madera_i2c_remove(struct i2c_client *i2c)
+{
+ struct madera *madera = dev_get_drvdata(&i2c->dev);
+
+ madera_dev_exit(madera);
+
+ return 0;
+}
+
+static const struct i2c_device_id madera_i2c_id[] = {
+ { "cs47l35", CS47L35 },
+ { "cs47l85", CS47L85 },
+ { "cs47l90", CS47L90 },
+ { "cs47l91", CS47L91 },
+ { "wm1840", WM1840 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, madera_i2c_id);
+
+static struct i2c_driver madera_i2c_driver = {
+ .driver = {
+ .name = "madera",
+ .pm = &madera_pm_ops,
+ .of_match_table = of_match_ptr(madera_of_match),
+ },
+ .probe = madera_i2c_probe,
+ .remove = madera_i2c_remove,
+ .id_table = madera_i2c_id,
+};
+
+module_i2c_driver(madera_i2c_driver);
+
+MODULE_DESCRIPTION("Madera I2C bus interface");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c
new file mode 100644
index 0000000..1252c59
--- /dev/null
+++ b/drivers/mfd/madera-spi.c
@@ -0,0 +1,135 @@
+/*
+ * SPI bus interface to Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * 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 <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#include <linux/mfd/madera/core.h>
+
+#include "madera.h"
+
+static int madera_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct madera *madera;
+ const struct regmap_config *regmap_16bit_config = NULL;
+ const struct regmap_config *regmap_32bit_config = NULL;
+ unsigned long type;
+ const char *name;
+ int ret;
+
+ if (spi->dev.of_node)
+ type = madera_get_type_from_of(&spi->dev);
+ else
+ type = id->driver_data;
+
+ switch (type) {
+ case CS47L35:
+ if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
+ regmap_16bit_config = &cs47l35_16bit_spi_regmap;
+ regmap_32bit_config = &cs47l35_32bit_spi_regmap;
+ }
+ break;
+ case CS47L85:
+ case WM1840:
+ if (IS_ENABLED(CONFIG_MFD_CS47L85)) {
+ regmap_16bit_config = &cs47l85_16bit_spi_regmap;
+ regmap_32bit_config = &cs47l85_32bit_spi_regmap;
+ }
+ break;
+ case CS47L90:
+ case CS47L91:
+ if (IS_ENABLED(CONFIG_MFD_CS47L90)) {
+ regmap_16bit_config = &cs47l90_16bit_spi_regmap;
+ regmap_32bit_config = &cs47l90_32bit_spi_regmap;
+ }
+ break;
+ default:
+ dev_err(&spi->dev,
+ "Unknown Madera SPI device type %ld\n", type);
+ return -EINVAL;
+ }
+
+ name = madera_name_from_type(type);
+
+ if (!regmap_16bit_config) {
+ dev_err(&spi->dev,
+ "Kernel does not include support for %s\n", name);
+ return -EINVAL;
+ }
+
+ madera = devm_kzalloc(&spi->dev, sizeof(*madera), GFP_KERNEL);
+ if (!madera)
+ return -ENOMEM;
+
+ madera->regmap = devm_regmap_init_spi(spi, regmap_16bit_config);
+ if (IS_ERR(madera->regmap)) {
+ ret = PTR_ERR(madera->regmap);
+ dev_err(&spi->dev,
+ "Failed to allocate 16-bit register map: %d\n", ret);
+ return ret;
+ }
+
+ madera->regmap_32bit = devm_regmap_init_spi(spi, regmap_32bit_config);
+ if (IS_ERR(madera->regmap_32bit)) {
+ ret = PTR_ERR(madera->regmap_32bit);
+ dev_err(&spi->dev,
+ "Failed to allocate 32-bit register map: %d\n", ret);
+ return ret;
+ }
+
+ madera->type = type;
+ madera->type_name = name;
+ madera->dev = &spi->dev;
+ madera->irq = spi->irq;
+
+ return madera_dev_init(madera);
+}
+
+static int madera_spi_remove(struct spi_device *spi)
+{
+ struct madera *madera = spi_get_drvdata(spi);
+
+ madera_dev_exit(madera);
+
+ return 0;
+}
+
+static const struct spi_device_id madera_spi_ids[] = {
+ { "cs47l35", CS47L35 },
+ { "cs47l85", CS47L85 },
+ { "cs47l90", CS47L90 },
+ { "cs47l91", CS47L91 },
+ { "wm1840", WM1840 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, madera_spi_ids);
+
+static struct spi_driver madera_spi_driver = {
+ .driver = {
+ .name = "madera",
+ .owner = THIS_MODULE,
+ .pm = &madera_pm_ops,
+ .of_match_table = of_match_ptr(madera_of_match),
+ },
+ .probe = madera_spi_probe,
+ .remove = madera_spi_remove,
+ .id_table = madera_spi_ids,
+};
+
+module_spi_driver(madera_spi_driver);
+
+MODULE_DESCRIPTION("Madera SPI bus interface");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/madera.h b/drivers/mfd/madera.h
new file mode 100644
index 0000000..645cba7
--- /dev/null
+++ b/drivers/mfd/madera.h
@@ -0,0 +1,54 @@
+/*
+ * MFD internals for Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MADERA_MFD_H
+#define MADERA_MFD_H
+
+#include <linux/of.h>
+#include <linux/pm.h>
+
+struct madera;
+
+extern const struct dev_pm_ops madera_pm_ops;
+extern const struct of_device_id madera_of_match[];
+
+int madera_dev_init(struct madera *madera);
+int madera_dev_exit(struct madera *madera);
+
+#ifdef CONFIG_OF
+unsigned long madera_get_type_from_of(struct device *dev);
+#else
+static inline unsigned long madera_get_type_from_of(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+const char *madera_name_from_type(enum madera_type type);
+
+extern const struct regmap_config cs47l35_16bit_spi_regmap;
+extern const struct regmap_config cs47l35_32bit_spi_regmap;
+extern const struct regmap_config cs47l35_16bit_i2c_regmap;
+extern const struct regmap_config cs47l35_32bit_i2c_regmap;
+int cs47l35_patch(struct madera *madera);
+
+extern const struct regmap_config cs47l85_16bit_spi_regmap;
+extern const struct regmap_config cs47l85_32bit_spi_regmap;
+extern const struct regmap_config cs47l85_16bit_i2c_regmap;
+extern const struct regmap_config cs47l85_32bit_i2c_regmap;
+int cs47l85_patch(struct madera *madera);
+
+extern const struct regmap_config cs47l90_16bit_spi_regmap;
+extern const struct regmap_config cs47l90_32bit_spi_regmap;
+extern const struct regmap_config cs47l90_16bit_i2c_regmap;
+extern const struct regmap_config cs47l90_32bit_i2c_regmap;
+int cs47l90_patch(struct madera *madera);
+
+#endif
diff --git a/include/linux/mfd/madera/core.h b/include/linux/mfd/madera/core.h
new file mode 100644
index 0000000..21ac543
--- /dev/null
+++ b/include/linux/mfd/madera/core.h
@@ -0,0 +1,179 @@
+/*
+ * MFD internals for Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MADERA_CORE_H
+#define MADERA_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+#include <linux/irqchip/irq-madera.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/regulator/consumer.h>
+#include <sound/madera-pdata.h>
+
+enum madera_type {
+ CS47L35 = 1,
+ CS47L85 = 2,
+ CS47L90 = 3,
+ CS47L91 = 4,
+ WM1840 = 7,
+};
+
+#define MADERA_MAX_CORE_SUPPLIES 2
+#define MADERA_MAX_GPIOS 40
+
+#define CS47L35_NUM_GPIOS 16
+#define CS47L85_NUM_GPIOS 40
+#define CS47L90_NUM_GPIOS 38
+
+#define MADERA_MAX_MICBIAS 4
+
+/* Notifier events */
+#define MADERA_NOTIFY_VOICE_TRIGGER 0x1
+#define MADERA_NOTIFY_HPDET 0x2
+#define MADERA_NOTIFY_MICDET 0x4
+
+/* GPIO Function Definitions */
+#define MADERA_GP_FN_ALTERNATE 0x00
+#define MADERA_GP_FN_GPIO 0x01
+#define MADERA_GP_FN_DSP_GPIO 0x02
+#define MADERA_GP_FN_IRQ1 0x03
+#define MADERA_GP_FN_IRQ2 0x04
+#define MADERA_GP_FN_FLL1_CLOCK 0x10
+#define MADERA_GP_FN_FLL2_CLOCK 0x11
+#define MADERA_GP_FN_FLL3_CLOCK 0x12
+#define MADERA_GP_FN_FLLAO_CLOCK 0x13
+#define MADERA_GP_FN_FLL1_LOCK 0x18
+#define MADERA_GP_FN_FLL2_LOCK 0x19
+#define MADERA_GP_FN_FLL3_LOCK 0x1A
+#define MADERA_GP_FN_FLLAO_LOCK 0x1B
+#define MADERA_GP_FN_OPCLK_OUT 0x40
+#define MADERA_GP_FN_OPCLK_ASYNC_OUT 0x41
+#define MADERA_GP_FN_PWM1 0x48
+#define MADERA_GP_FN_PWM2 0x49
+#define MADERA_GP_FN_SPDIF_OUT 0x4C
+#define MADERA_GP_FN_HEADPHONE_DET 0x50
+#define MADERA_GP_FN_MIC_DET 0x58
+#define MADERA_GP_FN_DRC1_SIGNAL_DETECT 0x80
+#define MADERA_GP_FN_DRC2_SIGNAL_DETECT 0x81
+#define MADERA_GP_FN_ASRC1_IN1_LOCK 0x88
+#define MADERA_GP_FN_ASRC1_IN2_LOCK 0x89
+#define MADERA_GP_FN_ASRC2_IN1_LOCK 0x8A
+#define MADERA_GP_FN_ASRC2_IN2_LOCK 0x8B
+#define MADERA_GP_FN_DSP_IRQ1 0xA0
+#define MADERA_GP_FN_DSP_IRQ2 0xA1
+#define MADERA_GP_FN_DSP_IRQ3 0xA2
+#define MADERA_GP_FN_DSP_IRQ4 0xA3
+#define MADERA_GP_FN_DSP_IRQ5 0xA4
+#define MADERA_GP_FN_DSP_IRQ6 0xA5
+#define MADERA_GP_FN_DSP_IRQ7 0xA6
+#define MADERA_GP_FN_DSP_IRQ8 0xA7
+#define MADERA_GP_FN_DSP_IRQ9 0xA8
+#define MADERA_GP_FN_DSP_IRQ10 0xA9
+#define MADERA_GP_FN_DSP_IRQ11 0xAA
+#define MADERA_GP_FN_DSP_IRQ12 0xAB
+#define MADERA_GP_FN_DSP_IRQ13 0xAC
+#define MADERA_GP_FN_DSP_IRQ14 0xAD
+#define MADERA_GP_FN_DSP_IRQ15 0xAE
+#define MADERA_GP_FN_DSP_IRQ16 0xAF
+#define MADERA_GP_FN_HPOUT1L_SC 0xB0
+#define MADERA_GP_FN_HPOUT1R_SC 0xB1
+#define MADERA_GP_FN_HPOUT2L_SC 0xB2
+#define MADERA_GP_FN_HPOUT2R_SC 0xB3
+#define MADERA_GP_FN_HPOUT3L_SC 0xB4
+#define MADERA_GP_FN_HPOUT4R_SC 0xB5
+#define MADERA_GP_FN_SPKOUTL_SC 0xB6
+#define MADERA_GP_FN_SPKOUTR_SC 0xB7
+#define MADERA_GP_FN_HPOUT1L_ENA 0xC0
+#define MADERA_GP_FN_HPOUT1R_ENA 0xC1
+#define MADERA_GP_FN_HPOUT2L_ENA 0xC2
+#define MADERA_GP_FN_HPOUT2R_ENA 0xC3
+#define MADERA_GP_FN_HPOUT3L_ENA 0xC4
+#define MADERA_GP_FN_HPOUT4R_ENA 0xC5
+#define MADERA_GP_FN_SPKOUTL_ENA 0xC6
+#define MADERA_GP_FN_SPKOUTR_ENA 0xC7
+#define MADERA_GP_FN_HPOUT1L_DIS 0xD0
+#define MADERA_GP_FN_HPOUT1R_DIS 0xD1
+#define MADERA_GP_FN_HPOUT2L_DIS 0xD2
+#define MADERA_GP_FN_HPOUT2R_DIS 0xD3
+#define MADERA_GP_FN_HPOUT3L_DIS 0xD4
+#define MADERA_GP_FN_HPOUT4R_DIS 0xD5
+#define MADERA_GP_FN_SPKOUTL_DIS 0xD6
+#define MADERA_GP_FN_SPKOUTR_DIS 0xD7
+#define MADERA_GP_FN_SPK_SHUTDOWN 0xE0
+#define MADERA_GP_FN_SPK_OVH_SHUTDOWN 0xE1
+#define MADERA_GP_FN_SPK_OVH_WARN 0xE2
+#define MADERA_GP_FN_TIMER1_STATUS 0x140
+#define MADERA_GP_FN_TIMER2_STATUS 0x141
+#define MADERA_GP_FN_TIMER3_STATUS 0x142
+#define MADERA_GP_FN_TIMER4_STATUS 0x143
+#define MADERA_GP_FN_TIMER5_STATUS 0x144
+#define MADERA_GP_FN_TIMER6_STATUS 0x145
+#define MADERA_GP_FN_TIMER7_STATUS 0x146
+#define MADERA_GP_FN_TIMER8_STATUS 0x147
+#define MADERA_GP_FN_EVENTLOG1_FIFO_STS 0x150
+#define MADERA_GP_FN_EVENTLOG2_FIFO_STS 0x151
+#define MADERA_GP_FN_EVENTLOG3_FIFO_STS 0x152
+#define MADERA_GP_FN_EVENTLOG4_FIFO_STS 0x153
+#define MADERA_GP_FN_EVENTLOG5_FIFO_STS 0x154
+#define MADERA_GP_FN_EVENTLOG6_FIFO_STS 0x155
+#define MADERA_GP_FN_EVENTLOG7_FIFO_STS 0x156
+#define MADERA_GP_FN_EVENTLOG8_FIFO_STS 0x157
+
+struct snd_soc_dapm_context;
+
+/*
+ * struct madera
+ *
+ * This should not be used by anything except child drivers of the Madera MFD
+ */
+struct madera {
+ struct regmap *regmap;
+ struct regmap *regmap_32bit;
+
+ struct device *dev;
+
+ enum madera_type type;
+ unsigned int rev;
+ const char *type_name;
+
+ struct gpio_desc *reset_gpio;
+
+ int num_core_supplies;
+ struct regulator_bulk_data core_supplies[MADERA_MAX_CORE_SUPPLIES];
+ struct regulator *dcvdd;
+ bool internal_dcvdd;
+
+ struct madera_pdata pdata;
+
+ struct device *irq_dev;
+ int irq;
+
+ unsigned int out_clamp[MADERA_MAX_OUTPUT];
+ unsigned int out_shorted[MADERA_MAX_OUTPUT];
+ unsigned int hp_ena;
+
+ unsigned int num_micbias;
+ unsigned int num_childbias[MADERA_MAX_MICBIAS];
+
+ struct snd_soc_dapm_context *dapm;
+
+ struct blocking_notifier_head notifier;
+};
+
+static inline int madera_call_notifiers(struct madera *madera,
+ unsigned long event,
+ void *data)
+{
+ return blocking_notifier_call_chain(&madera->notifier, event, data);
+}
+#endif
diff --git a/include/linux/mfd/madera/pdata.h b/include/linux/mfd/madera/pdata.h
new file mode 100644
index 0000000..b3af47c
--- /dev/null
+++ b/include/linux/mfd/madera/pdata.h
@@ -0,0 +1,61 @@
+/*
+ * Platform data for Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MADERA_PDATA_H
+#define MADERA_PDATA_H
+
+#include <linux/kernel.h>
+#include <linux/irqchip/irq-madera-pdata.h>
+#include <linux/regulator/arizona-ldo1.h>
+#include <linux/regulator/arizona-micsupp.h>
+#include <linux/regulator/machine.h>
+#include <sound/madera-pdata.h>
+
+#define MADERA_MAX_MICBIAS 4
+#define MADERA_MAX_CHILD_MICBIAS 4
+
+#define MADERA_MAX_GPSW 2
+
+struct pinctrl_map;
+
+/**
+ * struct madera_pdata - Configuration data for Madera devices
+ *
+ * @reset: GPIO controlling /RESET (0 = none)
+ * @ldo1: Substruct of pdata for the LDO1 regulator
+ * @micvdd: Substruct of pdata for the MICVDD regulator
+ * @irqchip: Substruct of pdata for the irqchip driver
+ * @gpio_base: Base GPIO number
+ * @gpio_configs: Array of GPIO configurations (See Documentation/pinctrl.txt)
+ * @n_gpio_configs: Number of entries in gpio_configs
+ * @codec: Substructure of pdata for the ASoC codec driver
+ * See include/sound/madera-pdata.h
+ * @gpsw: General purpose switch mode setting (See the SW1_MODE field
+ * in the datasheet for the available values for your codec)
+ */
+struct madera_pdata {
+ int reset;
+
+ struct arizona_ldo1_pdata ldo1;
+ struct arizona_micsupp_pdata micvdd;
+
+ struct madera_irqchip_pdata irqchip;
+
+ int gpio_base;
+
+ const struct pinctrl_map *gpio_configs;
+ int n_gpio_configs;
+
+ struct madera_codec_pdata codec;
+
+ u32 gpsw[MADERA_MAX_GPSW];
+};
+
+#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 12:00 +0200 |
| Subject | [PATCH v4 02/17] mfd: madera: Add DT bindings for Cirrus Logic Madera codecs |
| Message-ID | <u8adQ-247-13@gated-at.bofh.it> |
| In reply to | #1698638 |
Specification of the bindings for the parent MFD driver component
of the Cirrus Logic Madera codec drivers.
Note that although the interrupt controller and GPIO are child
drivers their required bindings are trivial, mandatory, and exist
within the parent MFD node so are documented here.
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
Acked-by: Rob Herring <robh@kernel.org>
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
---
Documentation/devicetree/bindings/mfd/madera.txt | 102 +++++++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/madera.txt
diff --git a/Documentation/devicetree/bindings/mfd/madera.txt b/Documentation/devicetree/bindings/mfd/madera.txt
new file mode 100644
index 0000000..db32660
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/madera.txt
@@ -0,0 +1,102 @@
+Cirrus Logic Madera class audio codecs Multi-Functional Device
+
+These devices are audio SoCs with extensive digital capabilities and a range
+of analogue I/O.
+
+See also the child driver bindings in:
+bindings/pinctrl/cirrus,madera-pinctrl.txt
+bindings/regulator/arizona-regulator.txt
+bindings/sound/madera.txt
+
+Required properties:
+
+ - compatible : One of the following chip-specific strings:
+ "cirrus,cs47l35"
+ "cirrus,cs47l85"
+ "cirrus,cs47l90"
+ "cirrus,cs47l91"
+ "cirrus,wm1840"
+
+ - reg : I2C slave address when connected using I2C, chip select number when
+ using SPI.
+
+ - DCVDD-supply : Power supply for the device as defined in
+ bindings/regulator/regulator.txt
+ Mandatory on CS47L35, CS47L90, CS47L91
+ Optional on CS47L85, WM1840
+
+ - AVDD-supply, DBVDD1-supply, DBVDD2-supply, CPVDD1-supply, CPVDD2-supply :
+ Power supplies for the device
+
+ - DBVDD3-supply, DBVDD4-supply : Power supplies for the device
+ (CS47L85, CS47L90, CS47L91, WM1840)
+
+ - SPKVDDL-supply, SPKVDDR-supply : Power supplies for the device
+ (CS47L85, WM1840)
+
+ - SPKVDD-supply : Power supply for the device
+ (CS47L35)
+
+ - interrupt-controller : Indicates that this device is an interrupt controller
+
+ - #interrupt-cells: the number of cells to describe an IRQ, must be 2.
+ The first cell is the IRQ number.
+ The second cell is the flags, encoded as the trigger masks from
+ bindings/interrupt-controller/interrupts.txt
+
+ - gpio-controller : Indicates this device is a GPIO controller.
+
+ - #gpio-cells : Must be 2. The first cell is the pin number. The second cell
+ is reserved for future use and must be zero
+
+ - interrupt-parent : The parent interrupt controller.
+
+ - interrupts : The interrupt line the /IRQ signal for the device is
+ connected to.
+
+Optional properties:
+
+ - MICVDD-supply : Power supply, only need to be specified if
+ powered externally
+
+ - reset-gpios : One entry specifying the GPIO controlling /RESET.
+ As defined in bindings/gpio.txt.
+ Although optional, it is strongly recommended to use a hardware reset
+
+ - MICBIASx : Initial data for the MICBIAS regulators, as covered in
+ Documentation/devicetree/bindings/regulator/regulator.txt.
+ One for each MICBIAS generator (MICBIAS1, MICBIAS2, ...)
+ (all codecs)
+
+ One for each output pin (MICBIAS1A, MIBCIAS1B, MICBIAS2A, ...)
+ (all except CS47L85, WM1840)
+
+ The following following additional property is supported for the generator
+ nodes:
+ - cirrus,ext-cap : Set to 1 if the MICBIAS has external decoupling
+ capacitors attached.
+
+Optional child nodes:
+ micvdd : Node containing initialization data for the micvdd regulator
+ See bindings/regulator/arizona-regulator.txt
+
+ ldo1 : Node containing initialization data for the LDO1 regulator
+ See bindings/regulator/arizona-regulator.txt
+ (cs47l85, wm1840)
+
+Example:
+
+cs47l85@0 {
+ compatible = "cirrus,cs47l85";
+ reg = <0>;
+
+ reset-gpios = <&gpio 0>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <&host_irq1>;
+ interrupt-parent = <&gic>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+};
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 12:00 +0200 |
| Subject | [PATCH v4 09/17] irqchip: Add driver for Cirrus Logic Madera codecs |
| Message-ID | <u8adR-247-21@gated-at.bofh.it> |
| In reply to | #1698638 |
The Cirrus Logic Madera codecs (Cirrus Logic CS47L35/85/90/91 and WM1840)
are highly complex devices containing up to 7 programmable DSPs and many
other internal sources of interrupts plus a number of GPIOs that can be
used as interrupt inputs. The large number (>150) of internal interrupt
sources are managed by an on-board interrupt controller.
This driver provides the handling for the interrupt controller. As the
codec is accessed via regmap, we can make use of the generic IRQ
functionality from regmap to do most of the work. Only around half of
the possible interrupt source are currently of interest from the driver
so only this subset is defined. Others can be added in future if needed.
The KConfig options are not user-configurable because this driver is
mandatory so is automatically included when the parent MFD driver is
selected.
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
No changes since V3
MAINTAINERS | 2 +
drivers/irqchip/Kconfig | 3 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-madera.c | 301 +++++++++++++++++++++++++++++++
include/linux/irqchip/irq-madera-pdata.h | 23 +++
include/linux/irqchip/irq-madera.h | 96 ++++++++++
6 files changed, 426 insertions(+)
create mode 100644 drivers/irqchip/irq-madera.c
create mode 100644 include/linux/irqchip/irq-madera-pdata.h
create mode 100644 include/linux/irqchip/irq-madera.h
diff --git a/MAINTAINERS b/MAINTAINERS
index f335b2a..bc07a32 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3377,7 +3377,9 @@ T: git https://github.com/CirrusLogic/linux-drivers.git
W: https://github.com/CirrusLogic/linux-drivers/wiki
S: Supported
F: Documentation/devicetree/bindings/mfd/madera.txt
+F: include/linux/irqchip/irq-madera*
F: include/linux/mfd/madera/*
+F: drivers/irqchip/irq-madera*
F: drivers/mfd/madera*
F: drivers/mfd/cs47l*
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index f1fd5f4..eb225ac 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -130,6 +130,9 @@ config IMGPDC_IRQ
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
+config MADERA_IRQ
+ bool
+
config IRQ_MIPS_CPU
bool
select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e88d856..388a5a2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
obj-$(CONFIG_CLPS711X_IRQCHIP) += irq-clps711x.o
obj-$(CONFIG_OR1K_PIC) += irq-or1k-pic.o
obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
diff --git a/drivers/irqchip/irq-madera.c b/drivers/irqchip/irq-madera.c
new file mode 100644
index 0000000..d80c459
--- /dev/null
+++ b/drivers/irqchip/irq-madera.c
@@ -0,0 +1,301 @@
+/*
+ * Interrupt support for Cirrus Logic Madera codecs
+ *
+ * Copyright 2016-2017 Cirrus Logic
+ *
+ * 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 <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/irqchip/irq-madera.h>
+#include <linux/irqchip/irq-madera-pdata.h>
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
+struct madera_irq_priv {
+ struct device *dev;
+ int irq;
+ struct regmap_irq_chip_data *irq_data;
+ struct madera *madera;
+};
+
+#define MADERA_IRQ(_irq, _reg) \
+ [MADERA_IRQ_ ## _irq] = { .reg_offset = (_reg) - MADERA_IRQ1_STATUS_2, \
+ .mask = MADERA_ ## _irq ## _EINT1 }
+
+static const struct regmap_irq madera_irqs[MADERA_NUM_IRQ] = {
+ MADERA_IRQ(FLL1_LOCK, MADERA_IRQ1_STATUS_2),
+ MADERA_IRQ(FLL2_LOCK, MADERA_IRQ1_STATUS_2),
+ MADERA_IRQ(FLL3_LOCK, MADERA_IRQ1_STATUS_2),
+ MADERA_IRQ(FLLAO_LOCK, MADERA_IRQ1_STATUS_2),
+
+ MADERA_IRQ(MICDET1, MADERA_IRQ1_STATUS_6),
+ MADERA_IRQ(MICDET2, MADERA_IRQ1_STATUS_6),
+ MADERA_IRQ(HPDET, MADERA_IRQ1_STATUS_6),
+
+ MADERA_IRQ(MICD_CLAMP_RISE, MADERA_IRQ1_STATUS_7),
+ MADERA_IRQ(MICD_CLAMP_FALL, MADERA_IRQ1_STATUS_7),
+ MADERA_IRQ(JD1_RISE, MADERA_IRQ1_STATUS_7),
+ MADERA_IRQ(JD1_FALL, MADERA_IRQ1_STATUS_7),
+
+ MADERA_IRQ(ASRC2_IN1_LOCK, MADERA_IRQ1_STATUS_9),
+ MADERA_IRQ(ASRC2_IN2_LOCK, MADERA_IRQ1_STATUS_9),
+ MADERA_IRQ(ASRC1_IN1_LOCK, MADERA_IRQ1_STATUS_9),
+ MADERA_IRQ(ASRC1_IN2_LOCK, MADERA_IRQ1_STATUS_9),
+ MADERA_IRQ(DRC2_SIG_DET, MADERA_IRQ1_STATUS_9),
+ MADERA_IRQ(DRC1_SIG_DET, MADERA_IRQ1_STATUS_9),
+
+ MADERA_IRQ(DSP_IRQ1, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ2, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ3, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ4, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ5, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ6, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ7, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ8, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ9, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ10, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ11, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ12, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ13, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ14, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ15, MADERA_IRQ1_STATUS_11),
+ MADERA_IRQ(DSP_IRQ16, MADERA_IRQ1_STATUS_11),
+
+ MADERA_IRQ(HP3R_SC, MADERA_IRQ1_STATUS_12),
+ MADERA_IRQ(HP3L_SC, MADERA_IRQ1_STATUS_12),
+ MADERA_IRQ(HP2R_SC, MADERA_IRQ1_STATUS_12),
+ MADERA_IRQ(HP2L_SC, MADERA_IRQ1_STATUS_12),
+ MADERA_IRQ(HP1R_SC, MADERA_IRQ1_STATUS_12),
+ MADERA_IRQ(HP1L_SC, MADERA_IRQ1_STATUS_12),
+
+ MADERA_IRQ(SPK_OVERHEAT_WARN, MADERA_IRQ1_STATUS_15),
+ MADERA_IRQ(SPK_OVERHEAT, MADERA_IRQ1_STATUS_15),
+
+ MADERA_IRQ(DSP1_BUS_ERR, MADERA_IRQ1_STATUS_33),
+ MADERA_IRQ(DSP2_BUS_ERR, MADERA_IRQ1_STATUS_33),
+ MADERA_IRQ(DSP3_BUS_ERR, MADERA_IRQ1_STATUS_33),
+ MADERA_IRQ(DSP4_BUS_ERR, MADERA_IRQ1_STATUS_33),
+ MADERA_IRQ(DSP5_BUS_ERR, MADERA_IRQ1_STATUS_33),
+ MADERA_IRQ(DSP6_BUS_ERR, MADERA_IRQ1_STATUS_33),
+ MADERA_IRQ(DSP7_BUS_ERR, MADERA_IRQ1_STATUS_33),
+};
+
+static const struct regmap_irq_chip madera_irq = {
+ .name = "madera IRQ",
+ .status_base = MADERA_IRQ1_STATUS_2,
+ .mask_base = MADERA_IRQ1_MASK_2,
+ .ack_base = MADERA_IRQ1_STATUS_2,
+ .runtime_pm = true,
+ .num_regs = 32,
+ .irqs = madera_irqs,
+ .num_irqs = ARRAY_SIZE(madera_irqs),
+};
+
+static int madera_map_irq(struct madera *madera, int irq)
+{
+ struct madera_irq_priv *priv = dev_get_drvdata(madera->irq_dev);
+
+ if (!madera->irq_dev)
+ return -ENOENT;
+
+ return regmap_irq_get_virq(priv->irq_data, irq);
+}
+
+int madera_request_irq(struct madera *madera, int irq, const char *name,
+ irq_handler_t handler, void *data)
+{
+ irq = madera_map_irq(madera, irq);
+
+ if (irq < 0)
+ return irq;
+
+ return request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT, name,
+ data);
+
+}
+EXPORT_SYMBOL_GPL(madera_request_irq);
+
+void madera_free_irq(struct madera *madera, int irq, void *data)
+{
+ irq = madera_map_irq(madera, irq);
+
+ if (irq < 0)
+ return;
+
+ free_irq(irq, data);
+}
+EXPORT_SYMBOL_GPL(madera_free_irq);
+
+int madera_set_irq_wake(struct madera *madera, int irq, int on)
+{
+ irq = madera_map_irq(madera, irq);
+
+ if (irq < 0)
+ return irq;
+
+ return irq_set_irq_wake(irq, on);
+}
+EXPORT_SYMBOL_GPL(madera_set_irq_wake);
+
+#ifdef CONFIG_PM_SLEEP
+static int madera_suspend_noirq(struct device *dev)
+{
+ struct madera_irq_priv *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "No IRQ suspend, reenabling IRQ\n");
+
+ enable_irq(priv->irq);
+
+ return 0;
+}
+
+static int madera_suspend(struct device *dev)
+{
+ struct madera_irq_priv *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "Suspend, disabling IRQ\n");
+
+ disable_irq(priv->irq);
+
+ return 0;
+}
+
+static int madera_resume_noirq(struct device *dev)
+{
+ struct madera_irq_priv *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "No IRQ resume, disabling IRQ\n");
+
+ disable_irq(priv->irq);
+
+ return 0;
+}
+
+static int madera_resume(struct device *dev)
+{
+ struct madera_irq_priv *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "Resume, reenabling IRQ\n");
+
+ enable_irq(priv->irq);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops madera_irq_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(madera_suspend, madera_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(madera_suspend_noirq,
+ madera_resume_noirq)
+};
+
+static int madera_irq_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct madera_irq_priv *priv;
+ struct irq_data *irq_data;
+ unsigned int irq_flags = madera->pdata.irqchip.irq_flags;
+ int ret;
+
+ dev_dbg(&pdev->dev, "probe\n");
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->madera = madera;
+ priv->irq = madera->irq;
+
+ /* Read the flags from the interrupt controller if not specified */
+ if (!irq_flags) {
+ irq_data = irq_get_irq_data(priv->irq);
+ if (!irq_data) {
+ dev_err(priv->dev, "Invalid IRQ: %d\n", priv->irq);
+ return -EINVAL;
+ }
+
+ irq_flags = irqd_get_trigger_type(irq_data);
+
+ /* Codec defaults to trigger low, use this if no flags given */
+ if (irq_flags == IRQ_TYPE_NONE)
+ irq_flags = IRQF_TRIGGER_LOW;
+ }
+
+ if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ dev_err(priv->dev, "Host interrupt not level-triggered\n");
+ return -EINVAL;
+ }
+
+ if (irq_flags & IRQF_TRIGGER_HIGH) {
+ ret = regmap_update_bits(madera->regmap, MADERA_IRQ1_CTRL,
+ MADERA_IRQ_POL_MASK, 0);
+ if (ret) {
+ dev_err(priv->dev,
+ "Failed to set IRQ polarity: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /*
+ * NOTE: regmap registers this against the OF node of the parent of
+ * the regmap - that is, against the mfd driver
+ */
+ ret = regmap_add_irq_chip(madera->regmap, priv->irq, IRQF_ONESHOT, 0,
+ &madera_irq, &priv->irq_data);
+ if (ret) {
+ dev_err(priv->dev, "add_irq_chip failed: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ madera->irq_dev = priv->dev;
+
+ return 0;
+}
+
+static int madera_irq_remove(struct platform_device *pdev)
+{
+ struct madera_irq_priv *priv = platform_get_drvdata(pdev);
+
+ /*
+ * The IRQ is disabled by the parent MFD driver before
+ * it starts cleaning up all child drivers
+ */
+
+ priv->madera->irq_dev = NULL;
+
+ regmap_del_irq_chip(priv->irq, priv->irq_data);
+ free_irq(priv->irq, priv);
+
+ return 0;
+}
+
+static struct platform_driver madera_irq_driver = {
+ .probe = madera_irq_probe,
+ .remove = madera_irq_remove,
+ .driver = {
+ .name = "madera-irq",
+ .pm = &madera_irq_pm_ops,
+ }
+};
+module_platform_driver(madera_irq_driver);
+
+MODULE_DESCRIPTION("Madera IRQ driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/irqchip/irq-madera-pdata.h b/include/linux/irqchip/irq-madera-pdata.h
new file mode 100644
index 0000000..1b6cc31
--- /dev/null
+++ b/include/linux/irqchip/irq-madera-pdata.h
@@ -0,0 +1,23 @@
+/*
+ * Platform data for Cirrus Logic Madera codecs irqchip driver
+ *
+ * Copyright 2016-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IRQCHIP_MADERA_PDATA_H
+#define IRQCHIP_MADERA_PDATA_H
+
+/**
+ * struct madera_irqchip_pdata - Configuration for Madera devices IRQ driver
+ *
+ * @irq_flags: Mode for primary IRQ (defaults to active low)
+ */
+struct madera_irqchip_pdata {
+ unsigned int irq_flags;
+};
+
+#endif
diff --git a/include/linux/irqchip/irq-madera.h b/include/linux/irqchip/irq-madera.h
new file mode 100644
index 0000000..8066846
--- /dev/null
+++ b/include/linux/irqchip/irq-madera.h
@@ -0,0 +1,96 @@
+/*
+ * Interrupt support for Cirrus Logic Madera codecs
+ *
+ * Copyright 2016-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IRQCHIP_MADERA_H
+#define IRQCHIP_MADERA_H
+
+#define MADERA_IRQ_FLL1_LOCK 0
+#define MADERA_IRQ_FLL2_LOCK 1
+#define MADERA_IRQ_FLL3_LOCK 2
+#define MADERA_IRQ_FLLAO_LOCK 3
+#define MADERA_IRQ_CLK_SYS_ERR 4
+#define MADERA_IRQ_CLK_ASYNC_ERR 5
+#define MADERA_IRQ_CLK_DSP_ERR 6
+#define MADERA_IRQ_HPDET 7
+#define MADERA_IRQ_MICDET1 8
+#define MADERA_IRQ_MICDET2 9
+#define MADERA_IRQ_JD1_RISE 10
+#define MADERA_IRQ_JD1_FALL 11
+#define MADERA_IRQ_JD2_RISE 12
+#define MADERA_IRQ_JD2_FALL 13
+#define MADERA_IRQ_MICD_CLAMP_RISE 14
+#define MADERA_IRQ_MICD_CLAMP_FALL 15
+#define MADERA_IRQ_DRC2_SIG_DET 16
+#define MADERA_IRQ_DRC1_SIG_DET 17
+#define MADERA_IRQ_ASRC1_IN1_LOCK 18
+#define MADERA_IRQ_ASRC1_IN2_LOCK 19
+#define MADERA_IRQ_ASRC2_IN1_LOCK 20
+#define MADERA_IRQ_ASRC2_IN2_LOCK 21
+#define MADERA_IRQ_DSP_IRQ1 22
+#define MADERA_IRQ_DSP_IRQ2 23
+#define MADERA_IRQ_DSP_IRQ3 24
+#define MADERA_IRQ_DSP_IRQ4 25
+#define MADERA_IRQ_DSP_IRQ5 26
+#define MADERA_IRQ_DSP_IRQ6 27
+#define MADERA_IRQ_DSP_IRQ7 28
+#define MADERA_IRQ_DSP_IRQ8 29
+#define MADERA_IRQ_DSP_IRQ9 30
+#define MADERA_IRQ_DSP_IRQ10 31
+#define MADERA_IRQ_DSP_IRQ11 32
+#define MADERA_IRQ_DSP_IRQ12 33
+#define MADERA_IRQ_DSP_IRQ13 34
+#define MADERA_IRQ_DSP_IRQ14 35
+#define MADERA_IRQ_DSP_IRQ15 36
+#define MADERA_IRQ_DSP_IRQ16 37
+#define MADERA_IRQ_HP1L_SC 38
+#define MADERA_IRQ_HP1R_SC 39
+#define MADERA_IRQ_HP2L_SC 40
+#define MADERA_IRQ_HP2R_SC 41
+#define MADERA_IRQ_HP3L_SC 42
+#define MADERA_IRQ_HP3R_SC 43
+#define MADERA_IRQ_SPKOUTL_SC 44
+#define MADERA_IRQ_SPKOUTR_SC 45
+#define MADERA_IRQ_HP1L_ENABLE_DONE 46
+#define MADERA_IRQ_HP1R_ENABLE_DONE 47
+#define MADERA_IRQ_HP2L_ENABLE_DONE 48
+#define MADERA_IRQ_HP2R_ENABLE_DONE 49
+#define MADERA_IRQ_HP3L_ENABLE_DONE 50
+#define MADERA_IRQ_HP3R_ENABLE_DONE 51
+#define MADERA_IRQ_SPKOUTL_ENABLE_DONE 52
+#define MADERA_IRQ_SPKOUTR_ENABLE_DONE 53
+#define MADERA_IRQ_SPK_SHUTDOWN 54
+#define MADERA_IRQ_SPK_OVERHEAT 55
+#define MADERA_IRQ_SPK_OVERHEAT_WARN 56
+#define MADERA_IRQ_GPIO1 57
+#define MADERA_IRQ_GPIO2 58
+#define MADERA_IRQ_GPIO3 59
+#define MADERA_IRQ_GPIO4 60
+#define MADERA_IRQ_GPIO5 61
+#define MADERA_IRQ_GPIO6 62
+#define MADERA_IRQ_GPIO7 63
+#define MADERA_IRQ_GPIO8 64
+#define MADERA_IRQ_DSP1_BUS_ERR 65
+#define MADERA_IRQ_DSP2_BUS_ERR 66
+#define MADERA_IRQ_DSP3_BUS_ERR 67
+#define MADERA_IRQ_DSP4_BUS_ERR 68
+#define MADERA_IRQ_DSP5_BUS_ERR 69
+#define MADERA_IRQ_DSP6_BUS_ERR 70
+#define MADERA_IRQ_DSP7_BUS_ERR 71
+
+#define MADERA_NUM_IRQ 72
+
+struct madera;
+
+int madera_request_irq(struct madera *madera, int irq, const char *name,
+ irq_handler_t handler, void *data);
+void madera_free_irq(struct madera *madera, int irq, void *data);
+int madera_set_irq_wake(struct madera *madera, int irq, int on);
+
+#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 12:00 +0200 |
| Subject | [PATCH v4 12/17] gpio: madera: Support Cirrus Logic Madera class codecs |
| Message-ID | <u8adR-247-29@gated-at.bofh.it> |
| In reply to | #1698638 |
This adds support for the GPIOs on Cirrus Logic Madera class codecs.
Any pins not used for special functions (see the pinctrl driver) can be
used as general single-bit input or output lines. The number of available
GPIOs varies between codecs.
Signed-off-by: Nariman Poushin <nariman@opensource.wolfsonmicro.com>
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
No changes since V3
MAINTAINERS | 1 +
drivers/gpio/Kconfig | 6 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-madera.c | 196 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 204 insertions(+)
create mode 100644 drivers/gpio/gpio-madera.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 4dbeaa3..22cc961 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3380,6 +3380,7 @@ F: Documentation/devicetree/bindings/mfd/madera.txt
F: Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
F: include/linux/irqchip/irq-madera*
F: include/linux/mfd/madera/*
+F: drivers/gpio/gpio-madera*
F: drivers/irqchip/irq-madera*
F: drivers/mfd/madera*
F: drivers/mfd/cs47l*
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f235eae..3679f68 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -975,6 +975,12 @@ config GPIO_LP87565
This driver can also be built as a module. If so, the module will be
called gpio-lp87565.
+config GPIO_MADERA
+ bool "Cirrus Logic Madera class codecs"
+ depends on PINCTRL_MADERA
+ help
+ Support for GPIOs on Cirrus Logic Madera class codecs.
+
config GPIO_MAX77620
tristate "GPIO support for PMIC MAX77620 and MAX20024"
depends on MFD_MAX77620
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a9fda6c..b036899 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
+obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c
new file mode 100644
index 0000000..e45905d5
--- /dev/null
+++ b/drivers/gpio/gpio-madera.c
@@ -0,0 +1,196 @@
+/*
+ * GPIO support for Cirrus Logic Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * 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 <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
+struct madera_gpio {
+ struct madera *madera;
+ struct gpio_chip gpio_chip;
+};
+
+static int madera_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct madera_gpio *madera_gpio = gpiochip_get_data(chip);
+ struct madera *madera = madera_gpio->madera;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(madera->regmap,
+ MADERA_GPIO1_CTRL_2 + (2 * offset), &val);
+ if (ret < 0)
+ return ret;
+
+ return (val & MADERA_GP1_DIR_MASK) >> MADERA_GP1_DIR_SHIFT;
+}
+
+static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
+{
+ struct madera_gpio *madera_gpio = gpiochip_get_data(chip);
+ struct madera *madera = madera_gpio->madera;
+
+ return regmap_update_bits(madera->regmap,
+ MADERA_GPIO1_CTRL_2 + (2 * offset),
+ MADERA_GP1_DIR_MASK, MADERA_GP1_DIR);
+}
+
+static int madera_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct madera_gpio *madera_gpio = gpiochip_get_data(chip);
+ struct madera *madera = madera_gpio->madera;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(madera->regmap,
+ MADERA_GPIO1_CTRL_1 + (2 * offset), &val);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & MADERA_GP1_LVL_MASK);
+}
+
+static int madera_gpio_direction_out(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct madera_gpio *madera_gpio = gpiochip_get_data(chip);
+ struct madera *madera = madera_gpio->madera;
+ unsigned int regval;
+ int ret;
+
+ if (value)
+ regval = MADERA_GP1_LVL;
+ else
+ regval = 0;
+
+ ret = regmap_update_bits(madera->regmap,
+ MADERA_GPIO1_CTRL_2 + (2 * offset),
+ MADERA_GP1_DIR_MASK, 0);
+ if (ret < 0)
+ return ret;
+
+ return regmap_update_bits(madera->regmap,
+ MADERA_GPIO1_CTRL_1 + (2 * offset),
+ MADERA_GP1_LVL_MASK, regval);
+}
+
+static void madera_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct madera_gpio *madera_gpio = gpiochip_get_data(chip);
+ struct madera *madera = madera_gpio->madera;
+ unsigned int regval;
+ int ret;
+
+ if (value)
+ regval = MADERA_GP1_LVL;
+ else
+ regval = 0;
+
+ ret = regmap_update_bits(madera->regmap,
+ MADERA_GPIO1_CTRL_1 + (2 * offset),
+ MADERA_GP1_LVL_MASK, regval);
+ if (ret)
+ dev_warn(madera->dev, "Failed to write to 0x%x (%d)\n",
+ MADERA_GPIO1_CTRL_1 + (2 * offset), ret);
+}
+
+static struct gpio_chip template_chip = {
+ .label = "madera",
+ .owner = THIS_MODULE,
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
+ .get_direction = madera_gpio_get_direction,
+ .direction_input = madera_gpio_direction_in,
+ .get = madera_gpio_get,
+ .direction_output = madera_gpio_direction_out,
+ .set = madera_gpio_set,
+ .set_config = gpiochip_generic_config,
+ .can_sleep = true,
+};
+
+static int madera_gpio_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct madera_pdata *pdata = dev_get_platdata(madera->dev);
+ struct madera_gpio *madera_gpio;
+ int ret;
+
+ madera_gpio = devm_kzalloc(&pdev->dev, sizeof(*madera_gpio),
+ GFP_KERNEL);
+ if (!madera_gpio)
+ return -ENOMEM;
+
+ madera_gpio->madera = madera;
+ madera_gpio->gpio_chip = template_chip;
+ madera_gpio->gpio_chip.parent = &pdev->dev;
+
+ if (IS_ENABLED(CONFIG_OF_GPIO))
+ madera_gpio->gpio_chip.of_node = madera->dev->of_node;
+
+ switch (madera->type) {
+ case CS47L35:
+ madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS;
+ break;
+ case CS47L85:
+ case WM1840:
+ madera_gpio->gpio_chip.ngpio = CS47L85_NUM_GPIOS;
+ break;
+ case CS47L90:
+ case CS47L91:
+ madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type);
+ return -EINVAL;
+ }
+
+ if (pdata && pdata->gpio_base)
+ madera_gpio->gpio_chip.base = pdata->gpio_base;
+ else
+ madera_gpio->gpio_chip.base = -1;
+
+ ret = devm_gpiochip_add_data(&pdev->dev, &madera_gpio->gpio_chip,
+ madera_gpio);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+ return ret;
+ }
+
+ ret = gpiochip_add_pin_range(&madera_gpio->gpio_chip, "madera-pinctrl",
+ 0, 0, madera_gpio->gpio_chip.ngpio);
+ if (ret) {
+ dev_warn(&pdev->dev, "Failed to add pin range (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver madera_gpio_driver = {
+ .driver.name = "madera-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = madera_gpio_probe,
+};
+
+module_platform_driver(madera_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO interface for Madera codecs");
+MODULE_AUTHOR("Nariman Poushin <nariman@opensource.wolfsonmicro.com>");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:madera-gpio");
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 12:00 +0200 |
| Subject | [PATCH v4 07/17] regulator: arizona-micsupp: Add support for Cirrus Logic Madera codecs |
| Message-ID | <u8adT-247-45@gated-at.bofh.it> |
| In reply to | #1698638 |
This adds a new driver identity "madera-micsupp" and probe function
so that this driver can be used to control the micsupp regulator on
Cirrus Logic Madera codecs.
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
Acked-by: Rob Herring <robh@kernel.org>
---
No changes since V3
.../bindings/regulator/arizona-regulator.txt | 3 +-
drivers/regulator/Kconfig | 7 ++-
drivers/regulator/arizona-micsupp.c | 71 +++++++++++++++++++++-
3 files changed, 76 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/regulator/arizona-regulator.txt b/Documentation/devicetree/bindings/regulator/arizona-regulator.txt
index 443564d..91b00f9 100644
--- a/Documentation/devicetree/bindings/regulator/arizona-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/arizona-regulator.txt
@@ -5,7 +5,8 @@ of analogue I/O.
This document lists regulator specific bindings, see the primary binding
document:
- ../mfd/arizona.txt
+ For Wolfson Arizona codecs: ../mfd/arizona.txt
+ For Cirrus Logic Madera codecs: ../mfd/madera.txt
Optional properties:
- wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362..ed5679f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -134,11 +134,12 @@ config REGULATOR_ARIZONA_LDO1
devices.
config REGULATOR_ARIZONA_MICSUPP
- tristate "Wolfson Arizona class devices MICSUPP"
- depends on MFD_ARIZONA
+ tristate "Cirrus Madera and Wolfson Arizona class devices MICSUPP"
+ depends on MFD_ARIZONA || MFD_MADERA
depends on SND_SOC
help
- Support for the MICSUPP regulators found on Wolfson Arizona class
+ Support for the MICSUPP regulators found on Cirrus Logic Madera codecs
+ and Wolfson Arizona codecs
devices.
config REGULATOR_AS3711
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index 120de94..36bf73c 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -30,6 +30,10 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
#include <linux/regulator/arizona-micsupp.h>
struct arizona_micsupp {
@@ -205,6 +209,28 @@ static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
.num_consumer_supplies = 1,
};
+static const struct regulator_desc madera_micsupp = {
+ .name = "MICVDD",
+ .supply_name = "CPVDD1",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 40,
+ .ops = &arizona_micsupp_ops,
+
+ .vsel_reg = MADERA_LDO2_CONTROL_1,
+ .vsel_mask = MADERA_LDO2_VSEL_MASK,
+ .enable_reg = MADERA_MIC_CHARGE_PUMP_1,
+ .enable_mask = MADERA_CPMIC_ENA,
+ .bypass_reg = MADERA_MIC_CHARGE_PUMP_1,
+ .bypass_mask = MADERA_CPMIC_BYPASS,
+
+ .linear_ranges = arizona_micsupp_ext_ranges,
+ .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
+
+ .enable_time = 3000,
+
+ .owner = THIS_MODULE,
+};
+
static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata,
struct regulator_config *config,
const struct regulator_desc *desc)
@@ -321,6 +347,24 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
&arizona->pdata.micvdd);
}
+static int madera_micsupp_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct arizona_micsupp *micsupp;
+
+ micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+ if (!micsupp)
+ return -ENOMEM;
+
+ micsupp->regmap = madera->regmap;
+ micsupp->dapm = &madera->dapm;
+ micsupp->dev = madera->dev;
+ micsupp->init_data = arizona_micsupp_ext_default;
+
+ return arizona_micsupp_common_init(pdev, micsupp, &madera_micsupp,
+ &madera->pdata.micvdd);
+}
+
static struct platform_driver arizona_micsupp_driver = {
.probe = arizona_micsupp_probe,
.driver = {
@@ -328,10 +372,35 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
},
};
-module_platform_driver(arizona_micsupp_driver);
+static struct platform_driver madera_micsupp_driver = {
+ .probe = madera_micsupp_probe,
+ .driver = {
+ .name = "madera-micsupp",
+ },
+};
+
+static struct platform_driver * const arizona_micsupp_drivers[] = {
+ &arizona_micsupp_driver,
+ &madera_micsupp_driver,
+};
+
+static int __init arizona_micsupp_init(void)
+{
+ return platform_register_drivers(arizona_micsupp_drivers,
+ ARRAY_SIZE(arizona_micsupp_drivers));
+}
+module_init(arizona_micsupp_init);
+
+static void __exit arizona_micsupp_exit(void)
+{
+ platform_unregister_drivers(arizona_micsupp_drivers,
+ ARRAY_SIZE(arizona_micsupp_drivers));
+}
+module_exit(arizona_micsupp_exit);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Arizona microphone supply driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-micsupp");
+MODULE_ALIAS("platform:madera-micsupp");
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
|---|---|
| Date | 2017-07-28 12:00 +0200 |
| Subject | [PATCH v4 10/17] pinctrl: madera: Add DT bindings for Cirrus Logic Madera codecs |
| Message-ID | <u8adS-247-41@gated-at.bofh.it> |
| In reply to | #1698638 |
This is the binding description of the pinctrl driver for Cirru Logic
Madera codecs. The binding uses the generic pinctrl binding so the main
purpose here is to describe the device-specific names for groups and
functions.
Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
Acked-by: Rob Herring <robh@kernel.org>
---
No changes since V3
.../bindings/pinctrl/cirrus,madera-pinctrl.txt | 99 ++++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
diff --git a/Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
new file mode 100644
index 0000000..b0e36cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
@@ -0,0 +1,99 @@
+Cirrus Logic Madera class audio codecs pinctrl driver
+
+The Cirrus Logic Madera codecs provide a number of GPIO functions for
+interfacing to external hardware and to provide logic outputs to other devices.
+Certain groups of GPIO pins also have an alternate function, normally as an
+audio interface.
+
+The set of available GPIOs, functions and alternate function groups differs
+between codecs so refer to the datasheet for the codec for further information
+on what is supported on that device.
+
+The properties for this driver exist within the parent MFD driver node.
+
+See also
+ the core bindings for the parent MFD driver:
+ Documentation/devicetree/bindings/mfd/madera.txt
+
+ the generic pinmix bindings:
+ Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Required properties of parent mfd node:
+ - pinctrl-names : must be "default"
+ - pinctrl-0 : a phandle to the node containing the subnodes containing default
+ configurations
+
+Required subnodes:
+ One subnode is required to contain the default settings. It contains an
+ arbitrary number of configuration subnodes, one for each group or pin
+ configuration you want to apply as a default.
+
+Required properties of configuration subnodes:
+ - groups : name of one pin group to configure. One of:
+ aif1, aif2, aif3, aif4, mif1, mif2, mif3, pdmspk1, pdmspk2,
+ dmic4, dmic5, dmic6,
+ gpio1, gpio2, ..., gpio40
+ The gpioN groups select the single pin of this name for configuration
+
+Optional properties of configuration subnodes:
+ Any configuration option not explicitly listed in the dts will be left at
+ chip default setting.
+
+ - function : name of function to assign to this group. One of:
+ aif1, aif2, aif3, aif4, mif1, mif2, mif3, pdmspk1, pdmspk2,
+ dmic3, dmic4, dmic5, dmic6,
+ io, dsp-gpio, irq1, irq2,
+ fll1-clk, fll1-lock, fll2-clk, fll2-lock, fll3-clk, fll3-lock,
+ fllao-clk, fllao-lock,
+ opclk, opclk-async, pwm1, pwm2, spdif,
+ asrc1-in1-lock, asrc1-in2-lock, asrc2-in1-lock, asrc2-in2-lock,
+ spkl-short-circuit, spkr-short-circuit, spk-shutdown,
+ spk-overheat-shutdown, spk-overheat-warn,
+ timer1-sts, timer2-sts, timer3-sts, timer4-sts, timer5-sts, timer6-sts,
+ timer7-sts, timer8-sts,
+ log1-fifo-ne, log2-fifo-ne, log3-fifo-ne, log4-fifo-ne, log5-fifo-ne,
+ log6-fifo-ne, log7-fifo-ne, log8-fifo-ne,
+
+ - bias-disable : disable pull-up and pull-down
+ - bias-bus-hold : enable buskeeper
+ - bias-pull-up : output is pulled-up
+ - bias-pull-down : output is pulled-down
+ - drive-push-pull : CMOS output
+ - drive-open-drain : open-drain output
+ - drive-strength : drive strength in mA. Valid values are 4 or 8
+ - input-schmitt-enable : enable schmitt-trigger mode
+ - input-schmitt-disable : disable schmitt-trigger mode
+ - input-debounce : A value of 0 disables debounce, a value !=0 enables
+ debounce
+ - output-low : set the pin to output mode with low level
+ - output-high : set the pin to output mode with high level
+
+Example:
+
+cs47l85@0 {
+ compatible = "cirrus,cs47l85";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&cs47l85_defaults>;
+
+ cs47l85_defaults: cs47l85-gpio-defaults {
+ aif1 {
+ groups = "aif1";
+ function = "aif1";
+ bias-bus-hold;
+ };
+
+ aif2 {
+ groups = "aif2";
+ function = "aif2";
+ bias-bus-hold;
+ };
+
+ opclk {
+ groups = "gpio1";
+ function = "opclk";
+ bias-pull-up;
+ drive-strength = <8>;
+ };
+ };
+};
--
1.9.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web