mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 10:08:59 +00:00
8f7a905ffb
The current driver has some troubles:
- Some groupings are wrong.
- The pinctrl group0 owns pins never used (at least in Openwrt) for any
pinmux. The driver hijacks all the pins on the group avoiding any other
use, spite they're free. I.e. for buttons, causing this kernel error:
[ 4.735928] gpio-keys-polled keys: unable to claim gpio 479, err=-22
[ 4.742642] gpio-keys-polled: probe of keys failed with error -22
- Minor errors about groupings on the documentation
- Missing "diag" grouping in dtsi
- Wrong groupings in dtsi
Fix it by setting the correct groups.
And relax the pin capturing, letting the gpios belonging to any group to
be used for other purposes like buttons. This was the behavior with stock
firmwares and old OpenWrt versions which never caused any trouble.
Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
(Cherry-picked from commit 50cb3a750f
)
411 lines
10 KiB
Diff
411 lines
10 KiB
Diff
From 45444cb631555e2dc16b95d779b10aa075c7482e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Gorski <jonas.gorski@gmail.com>
|
|
Date: Fri, 24 Jun 2016 22:14:13 +0200
|
|
Subject: [PATCH 05/16] pinctrl: add a pincontrol driver for BCM6348
|
|
|
|
Add a pincotrol driver for BCM6348. BCM6348 allow muxing five groups of
|
|
up to ten gpios into fourteen potential functions. It does not allow
|
|
muxing individual pins. Some functions require more than one group to be
|
|
muxed to the same function.
|
|
|
|
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
|
|
---
|
|
drivers/pinctrl/bcm63xx/Kconfig | 7 +
|
|
drivers/pinctrl/bcm63xx/Makefile | 1 +
|
|
drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c | 391 ++++++++++++++++++++++++++++++
|
|
3 files changed, 399 insertions(+)
|
|
create mode 100644 drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c
|
|
|
|
--- a/drivers/pinctrl/bcm63xx/Kconfig
|
|
+++ b/drivers/pinctrl/bcm63xx/Kconfig
|
|
@@ -8,3 +8,10 @@ config PINCTRL_BCM6328
|
|
select PINCONF
|
|
select PINCTRL_BCM63XX
|
|
select GENERIC_PINCONF
|
|
+
|
|
+config PINCTRL_BCM6348
|
|
+ bool "BCM6348 pincontrol driver" if COMPILE_TEST
|
|
+ select PINMUX
|
|
+ select PINCONF
|
|
+ select PINCTRL_BCM63XX
|
|
+ select GENERIC_PINCONF
|
|
--- a/drivers/pinctrl/bcm63xx/Makefile
|
|
+++ b/drivers/pinctrl/bcm63xx/Makefile
|
|
@@ -1,2 +1,3 @@
|
|
obj-$(CONFIG_PINCTRL_BCM63XX) += pinctrl-bcm63xx.o
|
|
obj-$(CONFIG_PINCTRL_BCM6328) += pinctrl-bcm6328.o
|
|
+obj-$(CONFIG_PINCTRL_BCM6348) += pinctrl-bcm6348.o
|
|
--- /dev/null
|
|
+++ b/drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c
|
|
@@ -0,0 +1,370 @@
|
|
+/*
|
|
+ * This file is subject to the terms and conditions of the GNU General Public
|
|
+ * License. See the file "COPYING" in the main directory of this archive
|
|
+ * for more details.
|
|
+ *
|
|
+ * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#include <linux/pinctrl/machine.h>
|
|
+#include <linux/pinctrl/pinconf.h>
|
|
+#include <linux/pinctrl/pinconf-generic.h>
|
|
+#include <linux/pinctrl/pinmux.h>
|
|
+
|
|
+#include "../core.h"
|
|
+#include "../pinctrl-utils.h"
|
|
+
|
|
+#include "pinctrl-bcm63xx.h"
|
|
+
|
|
+#define BCM6348_NGPIO 37
|
|
+
|
|
+#define MAX_GROUP 4
|
|
+#define PINS_PER_GROUP 8
|
|
+#define PIN_TO_GROUP(pin) (MAX_GROUP - ((pin) / PINS_PER_GROUP))
|
|
+#define GROUP_SHIFT(pin) (PIN_TO_GROUP(pin) * 4)
|
|
+#define GROUP_MASK(pin) (0xf << GROUP_SHIFT(pin))
|
|
+
|
|
+struct bcm6348_pingroup {
|
|
+ const char *name;
|
|
+ const unsigned * const pins;
|
|
+ const unsigned num_pins;
|
|
+};
|
|
+
|
|
+struct bcm6348_function {
|
|
+ const char *name;
|
|
+ const char * const *groups;
|
|
+ const unsigned num_groups;
|
|
+ unsigned int value;
|
|
+};
|
|
+
|
|
+struct bcm6348_pinctrl {
|
|
+ struct pinctrl_dev *pctldev;
|
|
+ struct pinctrl_desc desc;
|
|
+
|
|
+ void __iomem *mode;
|
|
+
|
|
+ /* register access lock */
|
|
+ spinlock_t lock;
|
|
+
|
|
+ struct gpio_chip gpio[2];
|
|
+};
|
|
+
|
|
+#define BCM6348_PIN(a, b, group) \
|
|
+ { \
|
|
+ .number = a, \
|
|
+ .name = b, \
|
|
+ .drv_data = (void *)(group), \
|
|
+ }
|
|
+
|
|
+static const struct pinctrl_pin_desc bcm6348_pins[] = {
|
|
+ BCM6348_PIN(0, "gpio0", 4),
|
|
+ BCM6348_PIN(1, "gpio1", 4),
|
|
+ BCM6348_PIN(2, "gpio2", 4),
|
|
+ BCM6348_PIN(3, "gpio3", 4),
|
|
+ BCM6348_PIN(4, "gpio4", 4),
|
|
+ BCM6348_PIN(5, "gpio5", 4),
|
|
+ BCM6348_PIN(6, "gpio6", 4),
|
|
+ BCM6348_PIN(7, "gpio7", 4),
|
|
+ BCM6348_PIN(8, "gpio8", 3),
|
|
+ BCM6348_PIN(9, "gpio9", 3),
|
|
+ BCM6348_PIN(10, "gpio10", 3),
|
|
+ BCM6348_PIN(11, "gpio11", 3),
|
|
+ BCM6348_PIN(12, "gpio12", 3),
|
|
+ BCM6348_PIN(13, "gpio13", 3),
|
|
+ BCM6348_PIN(14, "gpio14", 3),
|
|
+ BCM6348_PIN(15, "gpio15", 3),
|
|
+ BCM6348_PIN(16, "gpio16", 2),
|
|
+ BCM6348_PIN(17, "gpio17", 2),
|
|
+ BCM6348_PIN(18, "gpio18", 2),
|
|
+ BCM6348_PIN(19, "gpio19", 2),
|
|
+ BCM6348_PIN(20, "gpio20", 2),
|
|
+ BCM6348_PIN(21, "gpio21", 2),
|
|
+ BCM6348_PIN(22, "gpio22", 1),
|
|
+ BCM6348_PIN(23, "gpio23", 1),
|
|
+ BCM6348_PIN(24, "gpio24", 1),
|
|
+ BCM6348_PIN(25, "gpio25", 1),
|
|
+ BCM6348_PIN(26, "gpio26", 1),
|
|
+ BCM6348_PIN(27, "gpio27", 1),
|
|
+ BCM6348_PIN(28, "gpio28", 1),
|
|
+ BCM6348_PIN(29, "gpio29", 1),
|
|
+ BCM6348_PIN(30, "gpio30", 1),
|
|
+ BCM6348_PIN(31, "gpio31", 1),
|
|
+ BCM6348_PIN(32, "gpio32", 0),
|
|
+ BCM6348_PIN(33, "gpio33", 0),
|
|
+ BCM6348_PIN(34, "gpio34", 0),
|
|
+ BCM6348_PIN(35, "gpio35", 0),
|
|
+ BCM6348_PIN(36, "gpio36", 0),
|
|
+};
|
|
+
|
|
+enum bcm6348_muxes {
|
|
+ BCM6348_MUX_GPIO = 0,
|
|
+ BCM6348_MUX_EXT_EPHY,
|
|
+ BCM6348_MUX_MII_SNOOP,
|
|
+ BCM6348_MUX_LEGACY_LED,
|
|
+ BCM6348_MUX_MII_PCCARD,
|
|
+ BCM6348_MUX_PCI,
|
|
+ BCM6348_MUX_SPI_MASTER_UART,
|
|
+ BCM6348_MUX_EXT_MII,
|
|
+ BCM6348_MUX_UTOPIA,
|
|
+ BCM6348_MUX_DIAG,
|
|
+};
|
|
+
|
|
+static unsigned group0_pins[] = {
|
|
+ 32, 33, 34, 35, 36,
|
|
+};
|
|
+
|
|
+static unsigned group1_pins[] = {
|
|
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
+};
|
|
+
|
|
+static unsigned group2_pins[] = {
|
|
+ 16, 17, 18, 19, 20, 21,
|
|
+};
|
|
+
|
|
+static unsigned group3_pins[] = {
|
|
+ 8, 9, 10, 11, 12, 13, 14, 15,
|
|
+};
|
|
+
|
|
+static unsigned group4_pins[] = {
|
|
+ 0, 1, 2, 3, 4, 5, 6, 7,
|
|
+};
|
|
+
|
|
+#define BCM6348_GROUP(n) \
|
|
+ { \
|
|
+ .name = #n, \
|
|
+ .pins = n##_pins, \
|
|
+ .num_pins = ARRAY_SIZE(n##_pins), \
|
|
+ } \
|
|
+
|
|
+static struct bcm6348_pingroup bcm6348_groups[] = {
|
|
+ BCM6348_GROUP(group0),
|
|
+ BCM6348_GROUP(group1),
|
|
+ BCM6348_GROUP(group2),
|
|
+ BCM6348_GROUP(group3),
|
|
+ BCM6348_GROUP(group4),
|
|
+};
|
|
+
|
|
+static const char * const ext_mii_groups[] = {
|
|
+ "group0",
|
|
+ "group3",
|
|
+};
|
|
+
|
|
+static const char * const ext_ephy_groups[] = {
|
|
+ "group1",
|
|
+ "group4"
|
|
+};
|
|
+
|
|
+static const char * const mii_snoop_groups[] = {
|
|
+ "group1",
|
|
+ "group4",
|
|
+};
|
|
+
|
|
+static const char * const legacy_led_groups[] = {
|
|
+ "group4",
|
|
+};
|
|
+
|
|
+static const char * const mii_pccard_groups[] = {
|
|
+ "group1",
|
|
+};
|
|
+
|
|
+static const char * const pci_groups[] = {
|
|
+ "group2",
|
|
+};
|
|
+
|
|
+static const char * const spi_master_uart_groups[] = {
|
|
+ "group1",
|
|
+};
|
|
+
|
|
+static const char * const utopia_groups[] = {
|
|
+ "group1",
|
|
+ "group3",
|
|
+ "group4",
|
|
+};
|
|
+
|
|
+static const char * const diag_groups[] = {
|
|
+ "group0",
|
|
+ "group1",
|
|
+ "group2",
|
|
+ "group3",
|
|
+ "group4",
|
|
+};
|
|
+
|
|
+#define BCM6348_FUN(n, f) \
|
|
+ { \
|
|
+ .name = #n, \
|
|
+ .groups = n##_groups, \
|
|
+ .num_groups = ARRAY_SIZE(n##_groups), \
|
|
+ .value = BCM6348_MUX_##f, \
|
|
+ }
|
|
+
|
|
+static const struct bcm6348_function bcm6348_funcs[] = {
|
|
+ BCM6348_FUN(ext_mii, EXT_MII),
|
|
+ BCM6348_FUN(ext_ephy, EXT_EPHY),
|
|
+ BCM6348_FUN(mii_snoop, MII_SNOOP),
|
|
+ BCM6348_FUN(legacy_led, LEGACY_LED),
|
|
+ BCM6348_FUN(mii_pccard, MII_PCCARD),
|
|
+ BCM6348_FUN(pci, PCI),
|
|
+ BCM6348_FUN(spi_master_uart, SPI_MASTER_UART),
|
|
+ BCM6348_FUN(utopia, UTOPIA),
|
|
+ BCM6348_FUN(diag, DIAG),
|
|
+};
|
|
+
|
|
+static int bcm6348_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
|
|
+{
|
|
+ return ARRAY_SIZE(bcm6348_groups);
|
|
+}
|
|
+
|
|
+static const char *bcm6348_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
|
+ unsigned group)
|
|
+{
|
|
+ return bcm6348_groups[group].name;
|
|
+}
|
|
+
|
|
+static int bcm6348_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
|
+ unsigned group, const unsigned **pins,
|
|
+ unsigned *num_pins)
|
|
+{
|
|
+ *pins = bcm6348_groups[group].pins;
|
|
+ *num_pins = bcm6348_groups[group].num_pins;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bcm6348_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
|
|
+{
|
|
+ return ARRAY_SIZE(bcm6348_funcs);
|
|
+}
|
|
+
|
|
+static const char *bcm6348_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
|
|
+ unsigned selector)
|
|
+{
|
|
+ return bcm6348_funcs[selector].name;
|
|
+}
|
|
+
|
|
+static int bcm6348_pinctrl_get_groups(struct pinctrl_dev *pctldev,
|
|
+ unsigned selector,
|
|
+ const char * const **groups,
|
|
+ unsigned * const num_groups)
|
|
+{
|
|
+ *groups = bcm6348_funcs[selector].groups;
|
|
+ *num_groups = bcm6348_funcs[selector].num_groups;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void bcm6348_rmw_mux(struct bcm6348_pinctrl *pctl, u32 mask, u32 val)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ u32 reg;
|
|
+
|
|
+ spin_lock_irqsave(&pctl->lock, flags);
|
|
+
|
|
+ reg = __raw_readl(pctl->mode);
|
|
+ reg &= ~mask;
|
|
+ reg |= val & mask;
|
|
+ __raw_writel(reg, pctl->mode);
|
|
+
|
|
+ spin_unlock_irqrestore(&pctl->lock, flags);
|
|
+}
|
|
+
|
|
+static int bcm6348_pinctrl_set_mux(struct pinctrl_dev *pctldev,
|
|
+ unsigned selector, unsigned group)
|
|
+{
|
|
+ struct bcm6348_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
+ const struct bcm6348_pingroup *grp = &bcm6348_groups[group];
|
|
+ const struct bcm6348_function *f = &bcm6348_funcs[selector];
|
|
+ u32 mask, val;
|
|
+
|
|
+ /*
|
|
+ * pins n..(n+7) share the same group, so we only need to look at
|
|
+ * the first pin.
|
|
+ */
|
|
+ mask = GROUP_MASK(grp->pins[0]);
|
|
+ val = f->value << GROUP_SHIFT(grp->pins[0]);
|
|
+
|
|
+ bcm6348_rmw_mux(pctl, mask, val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct pinctrl_ops bcm6348_pctl_ops = {
|
|
+ .get_groups_count = bcm6348_pinctrl_get_group_count,
|
|
+ .get_group_name = bcm6348_pinctrl_get_group_name,
|
|
+ .get_group_pins = bcm6348_pinctrl_get_group_pins,
|
|
+#ifdef CONFIG_OF
|
|
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
|
|
+ .dt_free_map = pinctrl_utils_free_map,
|
|
+#endif
|
|
+};
|
|
+
|
|
+static struct pinmux_ops bcm6348_pmx_ops = {
|
|
+ .get_functions_count = bcm6348_pinctrl_get_func_count,
|
|
+ .get_function_name = bcm6348_pinctrl_get_func_name,
|
|
+ .get_function_groups = bcm6348_pinctrl_get_groups,
|
|
+ .set_mux = bcm6348_pinctrl_set_mux,
|
|
+ .strict = false,
|
|
+};
|
|
+
|
|
+static int bcm6348_pinctrl_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct bcm6348_pinctrl *pctl;
|
|
+ struct resource *res;
|
|
+ void __iomem *mode;
|
|
+
|
|
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mode");
|
|
+ mode = devm_ioremap_resource(&pdev->dev, res);
|
|
+ if (IS_ERR(mode))
|
|
+ return PTR_ERR(mode);
|
|
+
|
|
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
|
|
+ if (!pctl)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ spin_lock_init(&pctl->lock);
|
|
+
|
|
+ pctl->mode = mode;
|
|
+
|
|
+ /* disable all muxes by default */
|
|
+ __raw_writel(0, pctl->mode);
|
|
+
|
|
+ pctl->desc.name = dev_name(&pdev->dev);
|
|
+ pctl->desc.owner = THIS_MODULE;
|
|
+ pctl->desc.pctlops = &bcm6348_pctl_ops;
|
|
+ pctl->desc.pmxops = &bcm6348_pmx_ops;
|
|
+
|
|
+ pctl->desc.npins = ARRAY_SIZE(bcm6348_pins);
|
|
+ pctl->desc.pins = bcm6348_pins;
|
|
+
|
|
+ platform_set_drvdata(pdev, pctl);
|
|
+
|
|
+ pctl->pctldev = bcm63xx_pinctrl_register(pdev, &pctl->desc, pctl,
|
|
+ pctl->gpio, BCM6348_NGPIO);
|
|
+ if (IS_ERR(pctl->pctldev))
|
|
+ return PTR_ERR(pctl->pctldev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id bcm6348_pinctrl_match[] = {
|
|
+ { .compatible = "brcm,bcm6348-pinctrl", },
|
|
+ { },
|
|
+};
|
|
+
|
|
+static struct platform_driver bcm6348_pinctrl_driver = {
|
|
+ .probe = bcm6348_pinctrl_probe,
|
|
+ .driver = {
|
|
+ .name = "bcm6348-pinctrl",
|
|
+ .of_match_table = bcm6348_pinctrl_match,
|
|
+ },
|
|
+};
|
|
+
|
|
+builtin_platform_driver(bcm6348_pinctrl_driver);
|