From patchwork Fri Aug 19 10:53:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonas Gorski X-Patchwork-Id: 660806 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3sG0Fx75Bsz9t1b for ; Fri, 19 Aug 2016 20:54:13 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=ozQdzz04; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754580AbcHSKyL (ORCPT ); Fri, 19 Aug 2016 06:54:11 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:36231 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754365AbcHSKyK (ORCPT ); Fri, 19 Aug 2016 06:54:10 -0400 Received: by mail-wm0-f65.google.com with SMTP id i138so2934672wmf.3; Fri, 19 Aug 2016 03:54:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=9akdYOAx21d8HXWK7nDNJmWTei0j62cWrQMr/1rCTWg=; b=ozQdzz04w8W0A1mbmzeK42pMJ0VxZN2UcnUuJDmyYdyjccMMUFgs/WB3apfYhwP5AK J4og+sl8haTvr/lqqvXt/pMZZY7PXxk8ngk/ghKLkOZm258zyR8FH6ELhJ/XAe+AVQjK kdORjDQpAmEe0VLmlfS2zA7QJf4QIj704Un08UYn+zR2Ndsjo1US8u9Y1XJwAt0g7D/O hD9c3YyQLuD6BAd3CA6u0mG2TFR858zEXa3XCfSxtW+NqdwoUq8oDdXvAxFx6qLxwtzO X4oipkoLxgbkZ2tASP7VBqJ9H2Zi3KD7EFMkeMa4Ub2wgYZr9lxc5skpDgNv99T/klzQ Zv4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=9akdYOAx21d8HXWK7nDNJmWTei0j62cWrQMr/1rCTWg=; b=Izm59m5vwpVnJGCeCuviDL6lJ1HLI8mDhyZ5BnO2Ra1S4aPqS5pEFfkjWuQqWmpRt0 XBIRgdRZ/AmMTBREU0WPYKAf44+FIWwGsoAr912cuKUIr/lu+5yMnd7E6/UZlT4lBypt f6dabAXxUfFfIax0S1vCclZya9t04vXf0lDHejcVVkWXlvsEQbnBEjMEC84Ptgl0kQ/7 6TaoFNTHdeiibtI+Dx4NKARcpqomNn5WgLA6JaPHQHPYLQ0KfdH/iaTkAPOzLrBP2Jl7 V93xl5ugLrScTHTZC80ulW/mxNSqyQvw2ISXpd6S+mrW1Tq836klXXaS0+dsG0X6wSZN JIBQ== X-Gm-Message-State: AEkoouswrAQPSj46JVtAAW1BUZ2K60Yr0xfDRdqHQhX+/5RvmcThLP437L4JUcHPZa225w== X-Received: by 10.194.88.137 with SMTP id bg9mr5761926wjb.155.1471604048387; Fri, 19 Aug 2016 03:54:08 -0700 (PDT) Received: from localhost.localdomain ([2001:470:9e39::48e]) by smtp.gmail.com with ESMTPSA id g67sm3919066wme.5.2016.08.19.03.54.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 19 Aug 2016 03:54:07 -0700 (PDT) From: Jonas Gorski To: linux-gpio@vger.kernel.org Cc: Linus Walleij , devicetree@vger.kernel.org, Rob Herring , Mark Rutland , Kevin Cernekee , Florian Fainelli , =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Subject: [PATCH 05/13] pinctrl: add a pincontrol driver for BCM6348 Date: Fri, 19 Aug 2016 12:53:37 +0200 Message-Id: <1471604025-21575-6-git-send-email-jonas.gorski@gmail.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1471604025-21575-1-git-send-email-jonas.gorski@gmail.com> References: <1471604025-21575-1-git-send-email-jonas.gorski@gmail.com> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org 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 --- drivers/pinctrl/bcm63xx/Kconfig | 7 + drivers/pinctrl/bcm63xx/Makefile | 1 + drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c | 392 ++++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+) create mode 100644 drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c diff --git a/drivers/pinctrl/bcm63xx/Kconfig b/drivers/pinctrl/bcm63xx/Kconfig index 5084f66..5e19cfc 100644 --- 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 diff --git a/drivers/pinctrl/bcm63xx/Makefile b/drivers/pinctrl/bcm63xx/Makefile index 8b2472e..4dcfb10 100644 --- 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 diff --git a/drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c b/drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c new file mode 100644 index 0000000..3040550 --- /dev/null +++ b/drivers/pinctrl/bcm63xx/pinctrl-bcm6348.c @@ -0,0 +1,392 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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[] = { + "group0", + "group1", + "group3", +}; + +static const char * const diag_groups[] = { + "group0", + "group1", + "group2", + "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 group_num, mask, val; + + /* + * pins n..(n+7) share the same group, so we only need to look at + * the first pin. + */ + group_num = (unsigned long)bcm6348_pins[grp->pins[0]].drv_data; + mask = GROUP_MASK(group_num); + val = f->value << GROUP_SHIFT(group_num); + + bcm6348_rmw_mux(pctl, mask, val); + + return 0; +} + +static int bcm6348_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct bcm6348_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct pin_desc *desc; + u32 mask; + + /* don't reconfigure if already muxed */ + desc = pin_desc_get(pctldev, offset); + if (desc->mux_usecount) + return 0; + + mask = GROUP_MASK(offset); + + /* disable all functions using this pin */ + bcm6348_rmw_mux(pctl, mask, 0); + + 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, + .gpio_request_enable = bcm6348_gpio_request_enable, + .strict = true, +}; + +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);