Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/810606/?format=api
{ "id": 810606, "url": "http://patchwork.ozlabs.org/api/patches/810606/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/patch/1504704043-8052-12-git-send-email-rf@opensource.wolfsonmicro.com/", "project": { "id": 42, "url": "http://patchwork.ozlabs.org/api/projects/42/?format=api", "name": "Linux GPIO development", "link_name": "linux-gpio", "list_id": "linux-gpio.vger.kernel.org", "list_email": "linux-gpio@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1504704043-8052-12-git-send-email-rf@opensource.wolfsonmicro.com>", "list_archive_url": null, "date": "2017-09-06T13:20:37", "name": "[v5,11/17] pinctrl: madera: Add driver for Cirrus Logic Madera codecs", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "73d910af3d69711043d0ae72fb1013677dbbd475", "submitter": { "id": 65141, "url": "http://patchwork.ozlabs.org/api/people/65141/?format=api", "name": "Richard Fitzgerald", "email": "rf@opensource.wolfsonmicro.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-gpio/patch/1504704043-8052-12-git-send-email-rf@opensource.wolfsonmicro.com/mbox/", "series": [ { "id": 1804, "url": "http://patchwork.ozlabs.org/api/series/1804/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/list/?series=1804", "date": "2017-09-06T13:20:36", "name": "Add support for Cirrus Logic CS47L35/L85/L90/L91 codecs", "version": 5, "mbox": "http://patchwork.ozlabs.org/series/1804/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/810606/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/810606/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linux-gpio-owner@vger.kernel.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-gpio-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "ppops.net;\n\tspf=none smtp.mailfrom=rf@opensource.wolfsonmicro.com" ], "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xnPXv6qWPz9sNV\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 6 Sep 2017 23:28:15 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1754744AbdIFN0s (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tWed, 6 Sep 2017 09:26:48 -0400", "from mx0a-001ae601.pphosted.com ([67.231.149.25]:40628 \"EHLO\n\tmx0b-001ae601.pphosted.com\" rhost-flags-OK-OK-OK-FAIL)\n\tby vger.kernel.org with ESMTP id S1754568AbdIFNVC (ORCPT\n\t<rfc822; linux-gpio@vger.kernel.org>); Wed, 6 Sep 2017 09:21:02 -0400", "from pps.filterd (m0077473.ppops.net [127.0.0.1])\n\tby mx0a-001ae601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv86DJp4b032512; Wed, 6 Sep 2017 08:20:49 -0500", "from mail4.cirrus.com ([87.246.98.35])\n\tby mx0a-001ae601.pphosted.com with ESMTP id 2cqt20jwj0-1;\n\tWed, 06 Sep 2017 08:20:47 -0500", "from EX17.ad.cirrus.com (unknown [172.20.9.81])\n\tby mail4.cirrus.com (Postfix) with ESMTP id 9F962611CE8A;\n\tWed, 6 Sep 2017 08:20:44 -0500 (CDT)", "from imbe.wolfsonmicro.main (198.61.95.81) by EX17.ad.cirrus.com\n\t(172.20.9.81) with Microsoft SMTP Server id 14.3.301.0;\n\tWed, 6 Sep 2017 14:20:44 +0100", "from rf-debian.ad.cirrus.com (rf-debian.ad.cirrus.com\n\t[198.90.223.45]) by imbe.wolfsonmicro.main (8.14.4/8.14.4) with ESMTP\n\tid v86DKhDV032150; Wed, 6 Sep 2017 14:20:44 +0100" ], "From": "Richard Fitzgerald <rf@opensource.wolfsonmicro.com>", "To": "<lee.jones@linaro.org>, <broonie@kernel.org>,\n\t<linus.walleij@linaro.org>, <gnurou@gmail.com>,\n\t<robh+dt@kernel.org>, <tglx@linutronix.de>, <jason@lakedaemon.net>", "CC": "<alsa-devel@alsa-project.org>, <patches@opensource.wolfsonmicro.com>,\n\t<linux-gpio@vger.kernel.org>, <devicetree@vger.kernel.org>,\n\t<linux-kernel@vger.kernel.org>", "Subject": "[PATCH v5 11/17] pinctrl: madera: Add driver for Cirrus Logic\n\tMadera codecs", "Date": "Wed, 6 Sep 2017 14:20:37 +0100", "Message-ID": "<1504704043-8052-12-git-send-email-rf@opensource.wolfsonmicro.com>", "X-Mailer": "git-send-email 1.9.1", "In-Reply-To": "<1504704043-8052-1-git-send-email-rf@opensource.wolfsonmicro.com>", "References": "<1504704043-8052-1-git-send-email-rf@opensource.wolfsonmicro.com>", "MIME-Version": "1.0", "Content-Type": "text/plain", "X-Proofpoint-Spam-Details": "rule=notspam policy=default score=0\n\tpriorityscore=1501 malwarescore=0\n\tsuspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015\n\tlowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam\n\tadjust=0\n\treason=mlx scancount=1 engine=8.0.1-1707230000\n\tdefinitions=main-1709060186", "Sender": "linux-gpio-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<linux-gpio.vger.kernel.org>", "X-Mailing-List": "linux-gpio@vger.kernel.org" }, "content": "These codecs have a variable number of I/O lines each of which\nis individually selectable to a wide range of possible functions.\n\nThe functionality is slightly different from the traditional muxed\nGPIO since most of the functions can be mapped to any pin (and even\nthe same function to multiple pins). Most pins have a dedicated\n\"alternate\" function that is only available on that pin. The\nalternate functions are usually a group of signals, though it is\nnot always necessary to enable the full group, depending on the\nalternate function and how it is to be used. The mapping between\nalternate functions and GPIO pins varies between codecs depending\non the number of alternate functions and available pins.\n\nNote on the Kconfig options:\nThe formula \"default y if...\" is used for PINCTRL_MADERA so that its\nselect options will be processed, allowing us to group selects for\npinctrl into the pinctrl Kconfig where they logically belong instead\nof accumulating under the parent MFD Kconfig.\n\nSigned-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>\n---\nNo changes since V4\n\n MAINTAINERS | 2 +\n drivers/pinctrl/Kconfig | 1 +\n drivers/pinctrl/Makefile | 1 +\n drivers/pinctrl/cirrus/Kconfig | 15 +\n drivers/pinctrl/cirrus/Makefile | 11 +\n drivers/pinctrl/cirrus/pinctrl-cs47l35.c | 46 ++\n drivers/pinctrl/cirrus/pinctrl-cs47l85.c | 60 ++\n drivers/pinctrl/cirrus/pinctrl-cs47l90.c | 58 ++\n drivers/pinctrl/cirrus/pinctrl-madera.c | 1074 ++++++++++++++++++++++++++++++\n drivers/pinctrl/cirrus/pinctrl-madera.h | 40 ++\n 10 files changed, 1308 insertions(+)\n create mode 100644 drivers/pinctrl/cirrus/Kconfig\n create mode 100644 drivers/pinctrl/cirrus/Makefile\n create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs47l35.c\n create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs47l85.c\n create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs47l90.c\n create mode 100644 drivers/pinctrl/cirrus/pinctrl-madera.c\n create mode 100644 drivers/pinctrl/cirrus/pinctrl-madera.h", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex ed94481..9d75ab6 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -3426,11 +3426,13 @@ T:\tgit https://github.com/CirrusLogic/linux-drivers.git\n W:\thttps://github.com/CirrusLogic/linux-drivers/wiki\n S:\tSupported\n F:\tDocumentation/devicetree/bindings/mfd/madera.txt\n+F:\tDocumentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt\n F:\tinclude/linux/irqchip/irq-madera*\n F:\tinclude/linux/mfd/madera/*\n F:\tdrivers/irqchip/irq-madera*\n F:\tdrivers/mfd/madera*\n F:\tdrivers/mfd/cs47l*\n+F:\tdrivers/pinctrl/cirrus/*\n \n CLEANCACHE API\n M:\tKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>\ndiff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig\nindex 1778cf4..aeb2169 100644\n--- a/drivers/pinctrl/Kconfig\n+++ b/drivers/pinctrl/Kconfig\n@@ -368,6 +368,7 @@ source \"drivers/pinctrl/uniphier/Kconfig\"\n source \"drivers/pinctrl/vt8500/Kconfig\"\n source \"drivers/pinctrl/mediatek/Kconfig\"\n source \"drivers/pinctrl/zte/Kconfig\"\n+source \"drivers/pinctrl/cirrus/Kconfig\"\n \n config PINCTRL_XWAY\n \tbool\ndiff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile\nindex c16e279..a7e776f 100644\n--- a/drivers/pinctrl/Makefile\n+++ b/drivers/pinctrl/Makefile\n@@ -65,3 +65,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER)\t+= uniphier/\n obj-$(CONFIG_ARCH_VT8500)\t+= vt8500/\n obj-$(CONFIG_PINCTRL_MTK)\t+= mediatek/\n obj-$(CONFIG_PINCTRL_ZX)\t+= zte/\n+obj-y\t\t\t\t+= cirrus/\ndiff --git a/drivers/pinctrl/cirrus/Kconfig b/drivers/pinctrl/cirrus/Kconfig\nnew file mode 100644\nindex 0000000..093527ea\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/Kconfig\n@@ -0,0 +1,15 @@\n+config PINCTRL_MADERA\n+\tbool\n+\tselect PINMUX\n+\tselect GENERIC_PINCONF\n+\tdefault y if MFD_MADERA=y\n+\n+config PINCTRL_CS47L35\n+\tbool\n+\n+config PINCTRL_CS47L85\n+\tbool\n+\n+config PINCTRL_CS47L90\n+\tbool\n+\ndiff --git a/drivers/pinctrl/cirrus/Makefile b/drivers/pinctrl/cirrus/Makefile\nnew file mode 100644\nindex 0000000..b34473c\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/Makefile\n@@ -0,0 +1,11 @@\n+# Cirrus Logic pinctrl drivers\n+obj-$(CONFIG_PINCTRL_MADERA)\t+= pinctrl-madera.o\n+ifeq ($(CONFIG_PINCTRL_CS47L35),y)\n+obj-$(CONFIG_PINCTRL_MADERA)\t+= pinctrl-cs47l35.o\n+endif\n+ifeq ($(CONFIG_PINCTRL_CS47L85),y)\n+obj-$(CONFIG_PINCTRL_MADERA)\t+= pinctrl-cs47l85.o\n+endif\n+ifeq ($(CONFIG_PINCTRL_CS47L90),y)\n+obj-$(CONFIG_PINCTRL_MADERA)\t+= pinctrl-cs47l90.o\n+endif\ndiff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l35.c b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c\nnew file mode 100644\nindex 0000000..edf444a\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c\n@@ -0,0 +1,46 @@\n+/*\n+ * Pinctrl for Cirrus Logic CS47L35\n+ *\n+ * Copyright 2016-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#include <linux/err.h>\n+#include <linux/module.h>\n+\n+#include <linux/mfd/madera/core.h>\n+\n+#include \"pinctrl-madera.h\"\n+\n+/*\n+ * The alt func groups are the most commonly used functions we place these at\n+ * the lower function indexes for convenience, and the less commonly used gpio\n+ * functions at higher indexes.\n+ *\n+ * To stay consistent with the datasheet the function names are the same as\n+ * the group names for that function's pins\n+ *\n+ * Note - all 1 less than in datasheet because these are zero-indexed\n+ */\n+static const unsigned int cs47l35_aif3_pins[] = { 0, 1, 2, 3 };\n+static const unsigned int cs47l35_spk_pins[] = { 4, 5 };\n+static const unsigned int cs47l35_aif1_pins[] = { 7, 8, 9, 10 };\n+static const unsigned int cs47l35_aif2_pins[] = { 11, 12, 13, 14 };\n+static const unsigned int cs47l35_mif1_pins[] = { 6, 15 };\n+\n+static const struct madera_pin_groups cs47l35_pin_groups[] = {\n+\t{ \"aif1\", cs47l35_aif1_pins, ARRAY_SIZE(cs47l35_aif1_pins) },\n+\t{ \"aif2\", cs47l35_aif2_pins, ARRAY_SIZE(cs47l35_aif2_pins) },\n+\t{ \"aif3\", cs47l35_aif3_pins, ARRAY_SIZE(cs47l35_aif3_pins) },\n+\t{ \"mif1\", cs47l35_mif1_pins, ARRAY_SIZE(cs47l35_mif1_pins) },\n+\t{ \"pdmspk1\", cs47l35_spk_pins, ARRAY_SIZE(cs47l35_spk_pins) },\n+};\n+\n+const struct madera_pin_chip cs47l35_pin_chip = {\n+\t.n_pins = CS47L35_NUM_GPIOS,\n+\t.pin_groups = cs47l35_pin_groups,\n+\t.n_pin_groups = ARRAY_SIZE(cs47l35_pin_groups),\n+};\ndiff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l85.c b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c\nnew file mode 100644\nindex 0000000..63e34f8\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c\n@@ -0,0 +1,60 @@\n+/*\n+ * Pinctrl for Cirrus Logic CS47L85\n+ *\n+ * Copyright 2016-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#include <linux/err.h>\n+#include <linux/module.h>\n+\n+#include <linux/mfd/madera/core.h>\n+\n+#include \"pinctrl-madera.h\"\n+\n+/*\n+ * The alt func groups are the most commonly used functions we place these at\n+ * the lower function indexes for convenience, and the less commonly used gpio\n+ * functions at higher indexes.\n+ *\n+ * To stay consistent with the datasheet the function names are the same as\n+ * the group names for that function's pins\n+ *\n+ * Note - all 1 less than in datasheet because these are zero-indexed\n+ */\n+static const unsigned int cs47l85_mif1_pins[] = { 8, 9 };\n+static const unsigned int cs47l85_mif2_pins[] = { 10, 11 };\n+static const unsigned int cs47l85_mif3_pins[] = { 12, 13 };\n+static const unsigned int cs47l85_aif1_pins[] = { 14, 15, 16, 17 };\n+static const unsigned int cs47l85_aif2_pins[] = { 18, 19, 20, 21 };\n+static const unsigned int cs47l85_aif3_pins[] = { 22, 23, 24, 25 };\n+static const unsigned int cs47l85_aif4_pins[] = { 26, 27, 28, 29 };\n+static const unsigned int cs47l85_dmic4_pins[] = { 30, 31 };\n+static const unsigned int cs47l85_dmic5_pins[] = { 32, 33 };\n+static const unsigned int cs47l85_dmic6_pins[] = { 34, 35 };\n+static const unsigned int cs47l85_spk1_pins[] = { 36, 38 };\n+static const unsigned int cs47l85_spk2_pins[] = { 37, 39 };\n+\n+static const struct madera_pin_groups cs47l85_pin_groups[] = {\n+\t{ \"aif1\", cs47l85_aif1_pins, ARRAY_SIZE(cs47l85_aif1_pins) },\n+\t{ \"aif2\", cs47l85_aif2_pins, ARRAY_SIZE(cs47l85_aif2_pins) },\n+\t{ \"aif3\", cs47l85_aif3_pins, ARRAY_SIZE(cs47l85_aif3_pins) },\n+\t{ \"aif4\", cs47l85_aif4_pins, ARRAY_SIZE(cs47l85_aif4_pins) },\n+\t{ \"mif1\", cs47l85_mif1_pins, ARRAY_SIZE(cs47l85_mif1_pins) },\n+\t{ \"mif2\", cs47l85_mif2_pins, ARRAY_SIZE(cs47l85_mif2_pins) },\n+\t{ \"mif3\", cs47l85_mif3_pins, ARRAY_SIZE(cs47l85_mif3_pins) },\n+\t{ \"dmic4\", cs47l85_dmic4_pins, ARRAY_SIZE(cs47l85_dmic4_pins) },\n+\t{ \"dmic5\", cs47l85_dmic5_pins, ARRAY_SIZE(cs47l85_dmic5_pins) },\n+\t{ \"dmic6\", cs47l85_dmic6_pins, ARRAY_SIZE(cs47l85_dmic6_pins) },\n+\t{ \"pdmspk1\", cs47l85_spk1_pins, ARRAY_SIZE(cs47l85_spk1_pins) },\n+\t{ \"pdmspk2\", cs47l85_spk2_pins, ARRAY_SIZE(cs47l85_spk2_pins) },\n+};\n+\n+const struct madera_pin_chip cs47l85_pin_chip = {\n+\t.n_pins = CS47L85_NUM_GPIOS,\n+\t.pin_groups = cs47l85_pin_groups,\n+\t.n_pin_groups = ARRAY_SIZE(cs47l85_pin_groups),\n+};\ndiff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l90.c b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c\nnew file mode 100644\nindex 0000000..a1099b3\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c\n@@ -0,0 +1,58 @@\n+/*\n+ * Pinctrl for Cirrus Logic CS47L90\n+ *\n+ * Copyright 2016-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#include <linux/err.h>\n+#include <linux/module.h>\n+\n+#include <linux/mfd/madera/core.h>\n+\n+#include \"pinctrl-madera.h\"\n+\n+/*\n+ * The alt func groups are the most commonly used functions we place these at\n+ * the lower function indexes for convenience, and the less commonly used gpio\n+ * functions at higher indexes.\n+ *\n+ * To stay consistent with the datasheet the function names are the same as\n+ * the group names for that function's pins\n+ *\n+ * Note - all 1 less than in datasheet because these are zero-indexed\n+ */\n+static const unsigned int cs47l90_mif1_pins[] = { 8, 9 };\n+static const unsigned int cs47l90_mif2_pins[] = { 10, 11 };\n+static const unsigned int cs47l90_mif3_pins[] = { 12, 13 };\n+static const unsigned int cs47l90_aif1_pins[] = { 14, 15, 16, 17 };\n+static const unsigned int cs47l90_aif2_pins[] = { 18, 19, 20, 21 };\n+static const unsigned int cs47l90_aif3_pins[] = { 22, 23, 24, 25 };\n+static const unsigned int cs47l90_aif4_pins[] = { 26, 27, 28, 29 };\n+static const unsigned int cs47l90_dmic4_pins[] = { 30, 31 };\n+static const unsigned int cs47l90_dmic5_pins[] = { 32, 33 };\n+static const unsigned int cs47l90_dmic3_pins[] = { 34, 35 };\n+static const unsigned int cs47l90_spk1_pins[] = { 36, 37 };\n+\n+static const struct madera_pin_groups cs47l90_pin_groups[] = {\n+\t{ \"aif1\", cs47l90_aif1_pins, ARRAY_SIZE(cs47l90_aif1_pins) },\n+\t{ \"aif2\", cs47l90_aif2_pins, ARRAY_SIZE(cs47l90_aif2_pins) },\n+\t{ \"aif3\", cs47l90_aif3_pins, ARRAY_SIZE(cs47l90_aif3_pins) },\n+\t{ \"aif4\", cs47l90_aif4_pins, ARRAY_SIZE(cs47l90_aif4_pins) },\n+\t{ \"mif1\", cs47l90_mif1_pins, ARRAY_SIZE(cs47l90_mif1_pins) },\n+\t{ \"mif2\", cs47l90_mif2_pins, ARRAY_SIZE(cs47l90_mif2_pins) },\n+\t{ \"mif3\", cs47l90_mif3_pins, ARRAY_SIZE(cs47l90_mif3_pins) },\n+\t{ \"dmic3\", cs47l90_dmic3_pins, ARRAY_SIZE(cs47l90_dmic3_pins) },\n+\t{ \"dmic4\", cs47l90_dmic4_pins, ARRAY_SIZE(cs47l90_dmic4_pins) },\n+\t{ \"dmic5\", cs47l90_dmic5_pins, ARRAY_SIZE(cs47l90_dmic5_pins) },\n+\t{ \"pdmspk1\", cs47l90_spk1_pins, ARRAY_SIZE(cs47l90_spk1_pins) },\n+};\n+\n+const struct madera_pin_chip cs47l90_pin_chip = {\n+\t.n_pins = CS47L90_NUM_GPIOS,\n+\t.pin_groups = cs47l90_pin_groups,\n+\t.n_pin_groups = ARRAY_SIZE(cs47l90_pin_groups),\n+};\ndiff --git a/drivers/pinctrl/cirrus/pinctrl-madera.c b/drivers/pinctrl/cirrus/pinctrl-madera.c\nnew file mode 100644\nindex 0000000..3cdd43d\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/pinctrl-madera.c\n@@ -0,0 +1,1074 @@\n+/*\n+ * Pinctrl for Cirrus Logic Madera codecs\n+ *\n+ * Copyright 2016-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#include <linux/err.h>\n+#include <linux/module.h>\n+#include <linux/platform_device.h>\n+#include <linux/regmap.h>\n+#include <linux/slab.h>\n+#include <linux/pinctrl/pinctrl.h>\n+#include <linux/pinctrl/pinmux.h>\n+#include <linux/pinctrl/pinconf.h>\n+#include <linux/pinctrl/pinconf-generic.h>\n+\n+#include <linux/mfd/madera/core.h>\n+#include <linux/mfd/madera/registers.h>\n+\n+#include \"../pinctrl-utils.h\"\n+\n+#include \"pinctrl-madera.h\"\n+\n+/*\n+ * Use pin GPIO names for consistency\n+ * NOTE: IDs are zero-indexed for coding convenience\n+ */\n+static const struct pinctrl_pin_desc madera_pins[] = {\n+\tPINCTRL_PIN(0, \"gpio1\"),\n+\tPINCTRL_PIN(1, \"gpio2\"),\n+\tPINCTRL_PIN(2, \"gpio3\"),\n+\tPINCTRL_PIN(3, \"gpio4\"),\n+\tPINCTRL_PIN(4, \"gpio5\"),\n+\tPINCTRL_PIN(5, \"gpio6\"),\n+\tPINCTRL_PIN(6, \"gpio7\"),\n+\tPINCTRL_PIN(7, \"gpio8\"),\n+\tPINCTRL_PIN(8, \"gpio9\"),\n+\tPINCTRL_PIN(9, \"gpio10\"),\n+\tPINCTRL_PIN(10, \"gpio11\"),\n+\tPINCTRL_PIN(11, \"gpio12\"),\n+\tPINCTRL_PIN(12, \"gpio13\"),\n+\tPINCTRL_PIN(13, \"gpio14\"),\n+\tPINCTRL_PIN(14, \"gpio15\"),\n+\tPINCTRL_PIN(15, \"gpio16\"),\n+\tPINCTRL_PIN(16, \"gpio17\"),\n+\tPINCTRL_PIN(17, \"gpio18\"),\n+\tPINCTRL_PIN(18, \"gpio19\"),\n+\tPINCTRL_PIN(19, \"gpio20\"),\n+\tPINCTRL_PIN(20, \"gpio21\"),\n+\tPINCTRL_PIN(21, \"gpio22\"),\n+\tPINCTRL_PIN(22, \"gpio23\"),\n+\tPINCTRL_PIN(23, \"gpio24\"),\n+\tPINCTRL_PIN(24, \"gpio25\"),\n+\tPINCTRL_PIN(25, \"gpio26\"),\n+\tPINCTRL_PIN(26, \"gpio27\"),\n+\tPINCTRL_PIN(27, \"gpio28\"),\n+\tPINCTRL_PIN(28, \"gpio29\"),\n+\tPINCTRL_PIN(29, \"gpio30\"),\n+\tPINCTRL_PIN(30, \"gpio31\"),\n+\tPINCTRL_PIN(31, \"gpio32\"),\n+\tPINCTRL_PIN(32, \"gpio33\"),\n+\tPINCTRL_PIN(33, \"gpio34\"),\n+\tPINCTRL_PIN(34, \"gpio35\"),\n+\tPINCTRL_PIN(35, \"gpio36\"),\n+\tPINCTRL_PIN(36, \"gpio37\"),\n+\tPINCTRL_PIN(37, \"gpio38\"),\n+\tPINCTRL_PIN(38, \"gpio39\"),\n+\tPINCTRL_PIN(39, \"gpio40\"),\n+};\n+\n+/*\n+ * All single-pin functions can be mapped to any GPIO, however pinmux applies\n+ * functions to pin groups and only those groups declared as supporting that\n+ * function. To make this work we must put each pin in its own dummy group so\n+ * that the functions can be described as applying to all pins.\n+ * Since these do not correspond to anything in the actual hardware - they are\n+ * merely an adaptation to pinctrl's view of the world - we use the same name\n+ * as the pin to avoid confusion when comparing with datasheet instructions\n+ */\n+static const char * const madera_pin_single_group_names[] = {\n+\t\"gpio1\", \"gpio2\", \"gpio3\", \"gpio4\", \"gpio5\", \"gpio6\", \"gpio7\",\n+\t\"gpio8\", \"gpio9\", \"gpio10\", \"gpio11\", \"gpio12\", \"gpio13\", \"gpio14\",\n+\t\"gpio15\", \"gpio16\", \"gpio17\", \"gpio18\", \"gpio19\", \"gpio20\", \"gpio21\",\n+\t\"gpio22\", \"gpio23\", \"gpio24\", \"gpio25\", \"gpio26\", \"gpio27\", \"gpio28\",\n+\t\"gpio29\", \"gpio30\", \"gpio31\", \"gpio32\", \"gpio33\", \"gpio34\", \"gpio35\",\n+\t\"gpio36\", \"gpio37\", \"gpio38\", \"gpio39\", \"gpio40\",\n+};\n+\n+/* set of pin numbers for single-pin groups, zero-indexed */\n+static const unsigned int madera_pin_single_group_pins[] = {\n+\t 0, 1, 2, 3, 4, 5, 6,\n+\t 7, 8, 9, 10, 11, 12, 13,\n+\t 14, 15, 16, 17, 18, 19, 20,\n+\t 21, 22, 23, 24, 25, 26, 27,\n+\t 28, 29, 30, 31, 32, 33, 34,\n+\t 35, 36, 37, 38, 39,\n+};\n+\n+static const char * const madera_aif1_group_names[] = { \"aif1\" };\n+static const char * const madera_aif2_group_names[] = { \"aif2\" };\n+static const char * const madera_aif3_group_names[] = { \"aif3\" };\n+static const char * const madera_aif4_group_names[] = { \"aif4\" };\n+static const char * const madera_mif1_group_names[] = { \"mif1\" };\n+static const char * const madera_mif2_group_names[] = { \"mif2\" };\n+static const char * const madera_mif3_group_names[] = { \"mif3\" };\n+static const char * const madera_dmic3_group_names[] = { \"dmic3\" };\n+static const char * const madera_dmic4_group_names[] = { \"dmic4\" };\n+static const char * const madera_dmic5_group_names[] = { \"dmic5\" };\n+static const char * const madera_dmic6_group_names[] = { \"dmic6\" };\n+static const char * const madera_spk1_group_names[] = { \"pdmspk1\" };\n+static const char * const madera_spk2_group_names[] = { \"pdmspk2\" };\n+\n+/*\n+ * alt-functions always apply to a single pin group, other functions always\n+ * apply to all pins\n+ */\n+static const struct {\n+\tconst char *name;\n+\tconst char * const *group_names;\n+\tu32 func;\n+} madera_mux_funcs[] = {\n+\t{\n+\t\t.name = \"aif1\",\n+\t\t.group_names = madera_aif1_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"aif2\",\n+\t\t.group_names = madera_aif2_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"aif3\",\n+\t\t.group_names = madera_aif3_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"aif4\",\n+\t\t.group_names = madera_aif4_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"mif1\",\n+\t\t.group_names = madera_mif1_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"mif2\",\n+\t\t.group_names = madera_mif2_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"mif3\",\n+\t\t.group_names = madera_mif3_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"dmic3\",\n+\t\t.group_names = madera_dmic3_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"dmic4\",\n+\t\t.group_names = madera_dmic4_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"dmic5\",\n+\t\t.group_names = madera_dmic5_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"dmic6\",\n+\t\t.group_names = madera_dmic6_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"pdmspk1\",\n+\t\t.group_names = madera_spk1_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"pdmspk2\",\n+\t\t.group_names = madera_spk2_group_names,\n+\t\t.func = 0x000\n+\t},\n+\t{\n+\t\t.name = \"io\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x001\n+\t},\n+\t{\n+\t\t.name = \"dsp-gpio\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x002\n+\t},\n+\t{\n+\t\t.name = \"irq1\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x003\n+\t},\n+\t{\n+\t\t.name = \"irq2\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x004\n+\t},\n+\t{\n+\t\t.name = \"fll1-clk\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x010\n+\t},\n+\t{\n+\t\t.name = \"fll2-clk\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x011\n+\t},\n+\t{\n+\t\t.name = \"fll3-clk\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x012\n+\t},\n+\t{\n+\t\t.name = \"fllao-clk\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x013\n+\t},\n+\t{\n+\t\t.name = \"fll1-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x018\n+\t},\n+\t{\n+\t\t.name = \"fll2-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x019\n+\t},\n+\t{\n+\t\t.name = \"fll3-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x01a\n+\t},\n+\t{\n+\t\t.name = \"fllao-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x01b\n+\t},\n+\t{\n+\t\t.name = \"opclk\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x040\n+\t},\n+\t{\n+\t\t.name = \"opclk-async\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x041\n+\t},\n+\t{\n+\t\t.name = \"pwm1\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x048\n+\t},\n+\t{\n+\t\t.name = \"pwm2\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x049\n+\t},\n+\t{\n+\t\t.name = \"spdif\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x04c\n+\t},\n+\t{\n+\t\t.name = \"asrc1-in1-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x088\n+\t},\n+\t{\n+\t\t.name = \"asrc1-in2-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x089\n+\t},\n+\t{\n+\t\t.name = \"asrc2-in1-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x08a\n+\t},\n+\t{\n+\t\t.name = \"asrc2-in2-lock\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x08b\n+\t},\n+\t{\n+\t\t.name = \"spkl-short-circuit\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x0b6\n+\t},\n+\t{\n+\t\t.name = \"spkr-short-circuit\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x0b7\n+\t},\n+\t{\n+\t\t.name = \"spk-shutdown\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x0e0\n+\t},\n+\t{\n+\t\t.name = \"spk-overheat-shutdown\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x0e1\n+\t},\n+\t{\n+\t\t.name = \"spk-overheat-warn\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x0e2\n+\t},\n+\t{\n+\t\t.name = \"timer1-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x140\n+\t},\n+\t{\n+\t\t.name = \"timer2-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x141\n+\t},\n+\t{\n+\t\t.name = \"timer3-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x142\n+\t},\n+\t{\n+\t\t.name = \"timer4-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x143\n+\t},\n+\t{\n+\t\t.name = \"timer5-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x144\n+\t},\n+\t{\n+\t\t.name = \"timer6-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x145\n+\t},\n+\t{\n+\t\t.name = \"timer7-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x146\n+\t},\n+\t{\n+\t\t.name = \"timer8-sts\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x147\n+\t},\n+\t{\n+\t\t.name = \"log1-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x150\n+\t},\n+\t{\n+\t\t.name = \"log2-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x151\n+\t},\n+\t{\n+\t\t.name = \"log3-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x152\n+\t},\n+\t{\n+\t\t.name = \"log4-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x153\n+\t},\n+\t{\n+\t\t.name = \"log5-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x154\n+\t},\n+\t{\n+\t\t.name = \"log6-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x155\n+\t},\n+\t{\n+\t\t.name = \"log7-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x156\n+\t},\n+\t{\n+\t\t.name = \"log8-fifo-ne\",\n+\t\t.group_names = madera_pin_single_group_names,\n+\t\t.func = 0x157\n+\t},\n+};\n+\n+static u16 madera_pin_make_drv_str(struct madera_pin_private *priv,\n+\t\t\t\t unsigned int milliamps)\n+{\n+\tswitch (milliamps) {\n+\tcase 4:\n+\t\treturn 0;\n+\tcase 8:\n+\t\treturn 2 << MADERA_GP1_DRV_STR_SHIFT;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tdev_warn(priv->dev, \"%u mA not a valid drive strength\", milliamps);\n+\n+\treturn 0;\n+}\n+\n+static unsigned int madera_pin_unmake_drv_str(struct madera_pin_private *priv,\n+\t\t\t\t\t u16 regval)\n+{\n+\tregval = (regval & MADERA_GP1_DRV_STR_MASK) >> MADERA_GP1_DRV_STR_SHIFT;\n+\n+\tswitch (regval) {\n+\tcase 0:\n+\t\treturn 4;\n+\tcase 2:\n+\t\treturn 8;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+static int madera_get_groups_count(struct pinctrl_dev *pctldev)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\n+\t/* Number of alt function groups plus number of single-pin groups */\n+\treturn priv->chip->n_pin_groups + priv->chip->n_pins;\n+}\n+\n+static const char *madera_get_group_name(struct pinctrl_dev *pctldev,\n+\t\t\t\t\t unsigned int selector)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\n+\tif (selector < priv->chip->n_pin_groups) {\n+\t\treturn priv->chip->pin_groups[selector].name;\n+\t} else {\n+\t\tselector -= priv->chip->n_pin_groups;\n+\t\treturn madera_pin_single_group_names[selector];\n+\t}\n+}\n+\n+static int madera_get_group_pins(struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned int selector,\n+\t\t\t\t const unsigned int **pins,\n+\t\t\t\t unsigned int *num_pins)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\n+\tif (selector < priv->chip->n_pin_groups) {\n+\t\t*pins = priv->chip->pin_groups[selector].pins;\n+\t\t*num_pins = priv->chip->pin_groups[selector].n_pins;\n+\t} else {\n+\t\t/* return the dummy group for a single pin */\n+\t\tselector -= priv->chip->n_pin_groups;\n+\t\t*pins = &madera_pin_single_group_pins[selector];\n+\t\t*num_pins = 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static void madera_pin_dbg_show_fn(struct madera_pin_private *priv,\n+\t\t\t\t struct seq_file *s,\n+\t\t\t\t unsigned int pin, unsigned int fn)\n+{\n+\tconst struct madera_pin_chip *chip = priv->chip;\n+\tint i, g_pin;\n+\n+\tif (fn != 0) {\n+\t\tfor (i = 0; i < ARRAY_SIZE(madera_mux_funcs); ++i) {\n+\t\t\tif (madera_mux_funcs[i].func == fn) {\n+\t\t\t\tseq_printf(s, \" FN=%s\",\n+\t\t\t\t\t madera_mux_funcs[i].name);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t}\n+\t\treturn;\t/* ignore unknown function values */\n+\t}\n+\n+\t/* alt function */\n+\tfor (i = 0; i < chip->n_pin_groups; ++i) {\n+\t\tfor (g_pin = 0; g_pin < chip->pin_groups[i].n_pins; ++g_pin) {\n+\t\t\tif (chip->pin_groups[i].pins[g_pin] == pin) {\n+\t\t\t\tseq_printf(s, \" FN=%s\",\n+\t\t\t\t\t chip->pin_groups[i].name);\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+static void madera_pin_dbg_show(struct pinctrl_dev *pctldev,\n+\t\t\t\tstruct seq_file *s,\n+\t\t\t\tunsigned int pin)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tunsigned int conf[2];\n+\tunsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * pin);\n+\tunsigned int fn;\n+\tint ret;\n+\n+\tret = regmap_read(priv->madera->regmap, reg, &conf[0]);\n+\tif (ret)\n+\t\treturn;\n+\n+\tret = regmap_read(priv->madera->regmap, reg + 1, &conf[1]);\n+\tif (ret)\n+\t\treturn;\n+\n+\tseq_printf(s, \"%04x:%04x\", conf[0], conf[1]);\n+\n+\tfn = (conf[0] & MADERA_GP1_FN_MASK) >> MADERA_GP1_FN_SHIFT;\n+\tmadera_pin_dbg_show_fn(priv, s, pin, fn);\n+\n+\t/* State of direction bit is only relevant if function==1 */\n+\tif (fn == 1) {\n+\t\tif (conf[1] & MADERA_GP1_DIR_MASK)\n+\t\t\tseq_puts(s, \" IN\");\n+\t\telse\n+\t\t\tseq_puts(s, \" OUT\");\n+\t}\n+\n+\tif (conf[1] & MADERA_GP1_PU_MASK)\n+\t\tseq_puts(s, \" PU\");\n+\n+\tif (conf[1] & MADERA_GP1_PD_MASK)\n+\t\tseq_puts(s, \" PD\");\n+\n+\tif (conf[0] & MADERA_GP1_DB_MASK)\n+\t\tseq_puts(s, \" DB\");\n+\n+\tif (conf[0] & MADERA_GP1_OP_CFG_MASK)\n+\t\tseq_puts(s, \" OD\");\n+\telse\n+\t\tseq_puts(s, \" CMOS\");\n+\n+\tseq_printf(s, \" DRV=%umA\", madera_pin_unmake_drv_str(priv, conf[1]));\n+\n+\tif (conf[0] & MADERA_GP1_IP_CFG_MASK)\n+\t\tseq_puts(s, \"SCHMITT\");\n+}\n+\n+\n+static const struct pinctrl_ops madera_pin_group_ops = {\n+\t.get_groups_count = madera_get_groups_count,\n+\t.get_group_name = madera_get_group_name,\n+\t.get_group_pins = madera_get_group_pins,\n+\t.dt_node_to_map = pinconf_generic_dt_node_to_map_all,\n+\t.dt_free_map = pinctrl_utils_free_map,\n+#if IS_ENABLED(CONFIG_DEBUG_FS)\n+\t.pin_dbg_show = madera_pin_dbg_show,\n+#endif\n+};\n+\n+static int madera_mux_get_funcs_count(struct pinctrl_dev *pctldev)\n+{\n+\treturn ARRAY_SIZE(madera_mux_funcs);\n+}\n+\n+static const char *madera_mux_get_func_name(struct pinctrl_dev *pctldev,\n+\t\t\t\t\t unsigned int selector)\n+{\n+\treturn madera_mux_funcs[selector].name;\n+}\n+\n+static int madera_mux_get_groups(struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned int selector,\n+\t\t\t\t const char * const **groups,\n+\t\t\t\t unsigned int * const num_groups)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\n+\t*groups = madera_mux_funcs[selector].group_names;\n+\n+\tif (madera_mux_funcs[selector].func == 0) {\n+\t\t/* alt func always maps to a single group */\n+\t\t*num_groups = 1;\n+\t} else {\n+\t\t/* other funcs map to all available gpio pins */\n+\t\t*num_groups = priv->chip->n_pins;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int madera_mux_set_mux(struct pinctrl_dev *pctldev,\n+\t\t\t unsigned int selector,\n+\t\t\t unsigned int group)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tstruct madera *madera = priv->madera;\n+\tconst struct madera_pin_groups *pin_group = priv->chip->pin_groups;\n+\tunsigned int n_chip_groups = priv->chip->n_pin_groups;\n+\tconst char *func_name = madera_mux_funcs[selector].name;\n+\tunsigned int reg;\n+\tint i, ret;\n+\n+\tdev_dbg(priv->dev, \"%s selecting %u (%s) for group %u (%s)\\n\",\n+\t\t__func__, selector, func_name, group,\n+\t\tmadera_get_group_name(pctldev, group));\n+\n+\tif (madera_mux_funcs[selector].func == 0) {\n+\t\t/* alt func pin assignments are codec-specific */\n+\t\tfor (i = 0; i < n_chip_groups; ++i) {\n+\t\t\tif (strcmp(func_name, pin_group->name) == 0)\n+\t\t\t\tbreak;\n+\n+\t\t\t++pin_group;\n+\t\t}\n+\n+\t\tif (i == n_chip_groups)\n+\t\t\treturn -EINVAL;\n+\n+\t\tfor (i = 0; i < pin_group->n_pins; ++i) {\n+\t\t\treg = MADERA_GPIO1_CTRL_1 + (2 * pin_group->pins[i]);\n+\n+\t\t\tdev_dbg(priv->dev, \"%s setting 0x%x func bits to 0\\n\",\n+\t\t\t\t__func__, reg);\n+\n+\t\t\tret = regmap_update_bits(madera->regmap, reg,\n+\t\t\t\t\t\t MADERA_GP1_FN_MASK, 0);\n+\t\t\tif (ret)\n+\t\t\t\tbreak;\n+\n+\t\t}\n+\t} else {\n+\t\t/*\n+\t\t * for other funcs the group will be the gpio number and will\n+\t\t * be offset by the number of chip-specific functions at the\n+\t\t * start of the group list\n+\t\t */\n+\t\tgroup -= n_chip_groups;\n+\t\treg = MADERA_GPIO1_CTRL_1 + (2 * group);\n+\n+\t\tdev_dbg(priv->dev, \"%s setting 0x%x func bits to 0x%x\\n\",\n+\t\t\t__func__, reg, madera_mux_funcs[selector].func);\n+\n+\t\tret = regmap_update_bits(madera->regmap,\n+\t\t\t\t\t reg,\n+\t\t\t\t\t MADERA_GP1_FN_MASK,\n+\t\t\t\t\t madera_mux_funcs[selector].func);\n+\t}\n+\n+\tif (ret)\n+\t\tdev_err(priv->dev, \"Failed to write to 0x%x (%d)\\n\", reg, ret);\n+\n+\treturn ret;\n+}\n+\n+static int madera_gpio_set_direction(struct pinctrl_dev *pctldev,\n+\t\t\t\t struct pinctrl_gpio_range *range,\n+\t\t\t\t unsigned int offset,\n+\t\t\t\t bool input)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int reg = MADERA_GPIO1_CTRL_2 + (2 * offset);\n+\tunsigned int val;\n+\tint ret;\n+\n+\tif (input)\n+\t\tval = MADERA_GP1_DIR;\n+\telse\n+\t\tval = 0;\n+\n+\tret = regmap_update_bits(madera->regmap, reg, MADERA_GP1_DIR_MASK, val);\n+\tif (ret)\n+\t\tdev_err(priv->dev, \"Failed to write to 0x%x (%d)\\n\", reg, ret);\n+\n+\treturn ret;\n+}\n+\n+static int madera_gpio_request_enable(struct pinctrl_dev *pctldev,\n+\t\t\t\t struct pinctrl_gpio_range *range,\n+\t\t\t\t unsigned int offset)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * offset);\n+\tint ret;\n+\n+\t/* put the pin into GPIO mode */\n+\tret = regmap_update_bits(madera->regmap, reg, MADERA_GP1_FN_MASK, 1);\n+\tif (ret)\n+\t\tdev_err(priv->dev, \"Failed to write to 0x%x (%d)\\n\", reg, ret);\n+\n+\treturn ret;\n+}\n+\n+static void madera_gpio_disable_free(struct pinctrl_dev *pctldev,\n+\t\t\t\t struct pinctrl_gpio_range *range,\n+\t\t\t\t unsigned int offset)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tstruct madera *madera = priv->madera;\n+\tunsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * offset);\n+\tint ret;\n+\n+\t/* disable GPIO by setting to GPIO IN */\n+\tmadera_gpio_set_direction(pctldev, range, offset, true);\n+\n+\tret = regmap_update_bits(madera->regmap, reg, MADERA_GP1_FN_MASK, 1);\n+\tif (ret)\n+\t\tdev_err(priv->dev, \"Failed to write to 0x%x (%d)\\n\", reg, ret);\n+}\n+\n+static const struct pinmux_ops madera_pin_mux_ops = {\n+\t.get_functions_count = madera_mux_get_funcs_count,\n+\t.get_function_name = madera_mux_get_func_name,\n+\t.get_function_groups = madera_mux_get_groups,\n+\t.set_mux = madera_mux_set_mux,\n+\t.gpio_request_enable = madera_gpio_request_enable,\n+\t.gpio_disable_free = madera_gpio_disable_free,\n+\t.gpio_set_direction = madera_gpio_set_direction,\n+\t.strict = true, /* GPIO and other functions are exclusive */\n+};\n+\n+static int madera_pin_conf_get(struct pinctrl_dev *pctldev, unsigned int pin,\n+\t\t\t unsigned long *config)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tunsigned int param = pinconf_to_config_param(*config);\n+\tunsigned int result = 0;\n+\tunsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * pin);\n+\tunsigned int conf[2];\n+\tint ret;\n+\n+\tret = regmap_read(priv->madera->regmap, reg, &conf[0]);\n+\tif (!ret)\n+\t\tret = regmap_read(priv->madera->regmap, reg + 1, &conf[1]);\n+\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"Failed to read GP%d conf (%d)\\n\",\n+\t\t\tpin + 1, ret);\n+\t\treturn ret;\n+\t}\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_BIAS_BUS_HOLD:\n+\t\tconf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\tif (conf[1] == (MADERA_GP1_PU | MADERA_GP1_PD))\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_BIAS_DISABLE:\n+\t\tconf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\tif (!conf[1])\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\t\tconf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\tif (conf[1] == MADERA_GP1_PD_MASK)\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\tconf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\tif (conf[1] == MADERA_GP1_PU_MASK)\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_DRIVE_OPEN_DRAIN:\n+\t\tif (conf[0] & MADERA_GP1_OP_CFG_MASK)\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\t\tif (!(conf[0] & MADERA_GP1_OP_CFG_MASK))\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_DRIVE_STRENGTH:\n+\t\tresult = madera_pin_unmake_drv_str(priv, conf[1]);\n+\t\tbreak;\n+\tcase PIN_CONFIG_INPUT_DEBOUNCE:\n+\t\tif (conf[0] & MADERA_GP1_DB_MASK)\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\tif (conf[0] & MADERA_GP1_DIR_MASK)\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_INPUT_SCHMITT:\n+\tcase PIN_CONFIG_INPUT_SCHMITT_ENABLE:\n+\t\tif (conf[0] & MADERA_GP1_IP_CFG_MASK)\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tcase PIN_CONFIG_OUTPUT:\n+\t\tif ((conf[1] & MADERA_GP1_DIR_MASK) &&\n+\t\t (conf[0] & MADERA_GP1_LVL_MASK))\n+\t\t\tresult = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\t*config = pinconf_to_config_packed(param, result);\n+\n+\treturn 0;\n+}\n+\n+static int madera_pin_conf_set(struct pinctrl_dev *pctldev, unsigned int pin,\n+\t\t\t unsigned long *configs, unsigned int num_configs)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tu16 conf[2] = {0, 0};\n+\tu16 mask[2] = {0, 0};\n+\tunsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * pin);\n+\tunsigned int val;\n+\tint ret;\n+\n+\twhile (num_configs) {\n+\t\tdev_dbg(priv->dev, \"%s config 0x%lx\\n\", __func__, *configs);\n+\n+\t\tswitch (pinconf_to_config_param(*configs)) {\n+\t\tcase PIN_CONFIG_BIAS_BUS_HOLD:\n+\t\t\tmask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\t\tconf[1] |= MADERA_GP1_PU | MADERA_GP1_PD;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_DISABLE:\n+\t\t\tmask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\t\tconf[1] &= ~(MADERA_GP1_PU | MADERA_GP1_PD);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\t\t\tmask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\t\tconf[1] |= MADERA_GP1_PD;\n+\t\t\tconf[1] &= ~MADERA_GP1_PU;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\t\tmask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK;\n+\t\t\tconf[1] |= MADERA_GP1_PU;\n+\t\t\tconf[1] &= ~MADERA_GP1_PD;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_OPEN_DRAIN:\n+\t\t\tmask[0] |= MADERA_GP1_OP_CFG_MASK;\n+\t\t\tconf[0] |= MADERA_GP1_OP_CFG;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\t\t\tmask[0] |= MADERA_GP1_OP_CFG_MASK;\n+\t\t\tconf[0] &= ~MADERA_GP1_OP_CFG;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_STRENGTH:\n+\t\t\tval = pinconf_to_config_argument(*configs);\n+\t\t\tmask[1] |= MADERA_GP1_DRV_STR_MASK;\n+\t\t\tconf[1] &= ~MADERA_GP1_DRV_STR_MASK;\n+\t\t\tconf[1] |= madera_pin_make_drv_str(priv, val);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_DEBOUNCE:\n+\t\t\tmask[0] |= MADERA_GP1_DB_MASK;\n+\n+\t\t\t/*\n+\t\t\t * we can't configure debounce time per-pin so value\n+\t\t\t * is just a flag\n+\t\t\t */\n+\t\t\tval = pinconf_to_config_argument(*configs);\n+\t\t\tif (val)\n+\t\t\t\tconf[0] |= MADERA_GP1_DB;\n+\t\t\telse\n+\t\t\t\tconf[0] &= ~MADERA_GP1_DB;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\t\tval = pinconf_to_config_argument(*configs);\n+\t\t\tmask[1] |= MADERA_GP1_DIR_MASK;\n+\t\t\tif (val)\n+\t\t\t\tconf[1] |= MADERA_GP1_DIR;\n+\t\t\telse\n+\t\t\t\tconf[1] &= ~MADERA_GP1_DIR;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_SCHMITT:\n+\t\t\tval = pinconf_to_config_argument(*configs);\n+\t\t\tmask[0] |= MADERA_GP1_IP_CFG;\n+\t\t\tif (val)\n+\t\t\t\tconf[0] |= MADERA_GP1_IP_CFG;\n+\t\t\telse\n+\t\t\t\tconf[0] &= ~MADERA_GP1_IP_CFG;\n+\n+\t\t\tmask[1] |= MADERA_GP1_DIR_MASK;\n+\t\t\tconf[1] |= MADERA_GP1_DIR;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_SCHMITT_ENABLE:\n+\t\t\tmask[0] |= MADERA_GP1_IP_CFG;\n+\t\t\tconf[0] |= MADERA_GP1_IP_CFG;\n+\t\t\tmask[1] |= MADERA_GP1_DIR_MASK;\n+\t\t\tconf[1] |= MADERA_GP1_DIR;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_OUTPUT:\n+\t\t\tval = pinconf_to_config_argument(*configs);\n+\t\t\tmask[0] |= MADERA_GP1_LVL_MASK;\n+\t\t\tif (val)\n+\t\t\t\tconf[0] |= MADERA_GP1_LVL;\n+\t\t\telse\n+\t\t\t\tconf[0] &= ~MADERA_GP1_LVL;\n+\n+\t\t\tmask[1] |= MADERA_GP1_DIR_MASK;\n+\t\t\tconf[1] &= ~MADERA_GP1_DIR;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t++configs;\n+\t\t--num_configs;\n+\t}\n+\n+\tdev_dbg(priv->dev,\n+\t\t\"%s gpio%d 0x%x:0x%x 0x%x:0x%x\\n\",\n+\t\t__func__, pin + 1, reg, conf[0], reg + 1, conf[1]);\n+\n+\tret = regmap_update_bits(priv->madera->regmap, reg, mask[0], conf[0]);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\t++reg;\n+\tret = regmap_update_bits(priv->madera->regmap, reg, mask[1], conf[1]);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\treturn 0;\n+\n+err:\n+\tdev_err(priv->dev,\n+\t\t\"Failed to write GPIO%d conf (%d) reg 0x%x\\n\",\n+\t\tpin + 1, ret, reg);\n+\n+\treturn ret;\n+}\n+\n+static int madera_pin_conf_group_set(struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned int selector,\n+\t\t\t\t unsigned long *configs,\n+\t\t\t\t unsigned int num_configs)\n+{\n+\tstruct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tconst struct madera_pin_groups *pin_group;\n+\tunsigned int n_groups = priv->chip->n_pin_groups;\n+\tint i, ret;\n+\n+\tdev_dbg(priv->dev, \"%s setting group %s\\n\", __func__,\n+\t\tmadera_get_group_name(pctldev, selector));\n+\n+\tif (selector >= n_groups) {\n+\t\t/* group is a single pin, convert to pin number and set */\n+\t\treturn madera_pin_conf_set(pctldev,\n+\t\t\t\t\t selector - n_groups,\n+\t\t\t\t\t configs,\n+\t\t\t\t\t num_configs);\n+\t} else {\n+\t\tpin_group = &priv->chip->pin_groups[selector];\n+\n+\t\tfor (i = 0; i < pin_group->n_pins; ++i) {\n+\t\t\tret = madera_pin_conf_set(pctldev,\n+\t\t\t\t\t\t pin_group->pins[i],\n+\t\t\t\t\t\t configs,\n+\t\t\t\t\t\t num_configs);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const struct pinconf_ops madera_pin_conf_ops = {\n+\t.pin_config_get = madera_pin_conf_get,\n+\t.pin_config_set = madera_pin_conf_set,\n+\t.pin_config_group_set = madera_pin_conf_group_set,\n+\n+};\n+\n+static struct pinctrl_desc madera_pin_desc = {\n+\t.name = \"madera-pinctrl\",\n+\t.pins = madera_pins,\n+\t.pctlops = &madera_pin_group_ops,\n+\t.pmxops = &madera_pin_mux_ops,\n+\t.confops = &madera_pin_conf_ops,\n+\t.owner = THIS_MODULE,\n+};\n+\n+static int madera_pin_probe(struct platform_device *pdev)\n+{\n+\tstruct madera *madera = dev_get_drvdata(pdev->dev.parent);\n+\tconst struct madera_pdata *pdata = dev_get_platdata(madera->dev);\n+\tstruct madera_pin_private *priv;\n+\tint ret;\n+\n+\tBUILD_BUG_ON(ARRAY_SIZE(madera_pin_single_group_names) !=\n+\t\t ARRAY_SIZE(madera_pin_single_group_pins));\n+\n+\tdev_dbg(&pdev->dev, \"%s\\n\", __func__);\n+\n+\tpriv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->dev = &pdev->dev;\n+\tpriv->madera = madera;\n+\tpdev->dev.of_node = madera->dev->of_node;\n+\n+\tswitch (madera->type) {\n+\tcase CS47L35:\n+\t\tif (IS_ENABLED(CONFIG_PINCTRL_CS47L35))\n+\t\t\tpriv->chip = &cs47l35_pin_chip;\n+\t\tbreak;\n+\tcase CS47L85:\n+\tcase WM1840:\n+\t\tif (IS_ENABLED(CONFIG_PINCTRL_CS47L85))\n+\t\t\tpriv->chip = &cs47l85_pin_chip;\n+\t\tbreak;\n+\tcase CS47L90:\n+\tcase CS47L91:\n+\t\tif (IS_ENABLED(CONFIG_PINCTRL_CS47L90))\n+\t\t\tpriv->chip = &cs47l90_pin_chip;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (!priv->chip)\n+\t\treturn -ENODEV;\n+\n+\tmadera_pin_desc.npins = priv->chip->n_pins;\n+\n+\tret = devm_pinctrl_register_and_init(&pdev->dev,\n+\t\t\t\t\t &madera_pin_desc,\n+\t\t\t\t\t priv,\n+\t\t\t\t\t &priv->pctl);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"Failed pinctrl register (%d)\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* if the configuration is provided through pdata, apply it */\n+\tif (pdata) {\n+\t\tret = pinctrl_register_mappings(pdata->gpio_configs,\n+\t\t\t\t\t\tpdata->n_gpio_configs);\n+\t\tif (ret) {\n+\t\t\tdev_err(priv->dev,\n+\t\t\t\t\"Failed to register pdata mappings (%d)\\n\",\n+\t\t\t\tret);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tret = pinctrl_enable(priv->pctl);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"Failed to enable pinctrl (%d)\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tdev_dbg(priv->dev, \"pinctrl probed ok\\n\");\n+\n+\treturn 0;\n+}\n+\n+static struct platform_driver madera_pin_driver = {\n+\t.probe = madera_pin_probe,\n+\t.driver = {\n+\t\t.name = \"madera-pinctrl\",\n+\t},\n+};\n+\n+module_platform_driver(madera_pin_driver);\n+\n+MODULE_DESCRIPTION(\"Madera pinctrl driver\");\n+MODULE_AUTHOR(\"Richard Fitzgerald <rf@opensource.wolfsonmicro.com>\");\n+MODULE_LICENSE(\"GPL v2\");\ndiff --git a/drivers/pinctrl/cirrus/pinctrl-madera.h b/drivers/pinctrl/cirrus/pinctrl-madera.h\nnew file mode 100644\nindex 0000000..7b55e22\n--- /dev/null\n+++ b/drivers/pinctrl/cirrus/pinctrl-madera.h\n@@ -0,0 +1,40 @@\n+/*\n+ * Pinctrl for Cirrus Logic Madera codecs\n+ *\n+ * Copyright 2016-2017 Cirrus Logic\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#ifndef PINCTRL_MADERA_H\n+#define PINCTRL_MADERA_H\n+\n+struct madera_pin_groups {\n+\tconst char *name;\n+\tconst unsigned int *pins;\n+\tunsigned int n_pins;\n+};\n+\n+struct madera_pin_chip {\n+\tunsigned int n_pins;\n+\n+\tconst struct madera_pin_groups *pin_groups;\n+\tunsigned int n_pin_groups;\n+};\n+\n+struct madera_pin_private {\n+\tstruct madera *madera;\n+\n+\tconst struct madera_pin_chip *chip; /* chip-specific groups */\n+\n+\tstruct device *dev;\n+\tstruct pinctrl_dev *pctl;\n+};\n+\n+extern const struct madera_pin_chip cs47l35_pin_chip;\n+extern const struct madera_pin_chip cs47l85_pin_chip;\n+extern const struct madera_pin_chip cs47l90_pin_chip;\n+\n+#endif\n", "prefixes": [ "v5", "11/17" ] }