From patchwork Wed Apr 13 10:43:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Abraham X-Patchwork-Id: 610039 X-Patchwork-Delegate: promsoft@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3qlQtY2yP3z9t49 for ; Thu, 14 Apr 2016 00:20:05 +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=fTyHm0RX; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D4EF0A76EE; Wed, 13 Apr 2016 16:19:52 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id G-Iwob1eMwKS; Wed, 13 Apr 2016 16:19:52 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3001DA76B4; Wed, 13 Apr 2016 16:19:34 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B6821A75F6 for ; Wed, 13 Apr 2016 11:47:24 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hVBl1_LNGf-j for ; Wed, 13 Apr 2016 11:47:24 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pa0-f66.google.com (mail-pa0-f66.google.com [209.85.220.66]) by theia.denx.de (Postfix) with ESMTPS id DE3CFA748A for ; Wed, 13 Apr 2016 11:47:23 +0200 (CEST) Received: by mail-pa0-f66.google.com with SMTP id hb4so3479200pac.1 for ; Wed, 13 Apr 2016 02:47:23 -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=L36cENMRrQIyKxCdZpHvyQTdeP12jr9W5LZt+FMGU9I=; b=fTyHm0RXbaw1DLHZkPoGgbUYwQkcotfyTiG2Rmoq7V4nwmd7R5NoHQ5/X/zOI4owQc EwSNd8DWtZz0LvHfn5aQoMswHNZ/9kL/c5NLeLZUi+djxzYAO1grXK9UxtCV1iPUWvuQ HvmsI43nNcAc1PZbnSXzG8LfO1L0AnQpuPOFa5GzS/PCL9jUrTO6sgPdVCPLV39lE/oq XPxsmbjLnuLwL8UuKEOamcKpB+3juHGggL+u+fVe4/6oqT9YboFEqlmLTh1qjPh3qW6r ol/0wB/6X9CQwq6Pcni2s4/FXD9N0GGRaDwrmNZLFpBS/2aIKdMxfSME52qAssKbTa2n VOYg== 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=L36cENMRrQIyKxCdZpHvyQTdeP12jr9W5LZt+FMGU9I=; b=cn4XUGL5TGAmnYAupA/HtjKYC+WhF7j4da1suzDuKAX5Rb3+inlXy+T2KBOL6/WFMz ofERMZRl9NxEuiObKzDKUQLs0Len/sJfhFWetXbHuTMLp/Bf9XQqmBOPJwj3EOthIsoi 0IAcb5v7rb5uBz3HnZtRNzv36muhDnwoNqZWuCvIvh32SfiDjH3RQP9E725mRqqPv/lb 5DskbSAz+EGlBAm1H015xBj6tafvC0O8t1Lo1QkzP8e/GOk3siz/MWC0k1/oqXhAz/qm IQcRIX7HMImyK/vQZJU8grUm5JoTLDBWCjm6MPWdcH7t9sXgH5wsa+eLZX7bNDfdcI9+ +CZQ== X-Gm-Message-State: AOPr4FUwE6EJ+8Xl6rdv7oRbyVEIa4BPXyidRmSOcHrSk/G8ijUSWRkZ1WvtwBnicoy3CQ== X-Received: by 10.66.26.198 with SMTP id n6mr11488780pag.4.1460540842456; Wed, 13 Apr 2016 02:47:22 -0700 (PDT) Received: from user-ubuntu.sisodomain.com ([103.58.156.161]) by smtp.gmail.com with ESMTPSA id lq10sm49762686pab.36.2016.04.13.02.47.17 (version=TLS1_1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 13 Apr 2016 02:47:21 -0700 (PDT) From: Thomas Abraham To: u-boot@lists.denx.de Date: Wed, 13 Apr 2016 16:13:35 +0530 Message-Id: <1460544222-5342-3-git-send-email-ta.omasab@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1460544222-5342-1-git-send-email-ta.omasab@gmail.com> References: <1460544222-5342-1-git-send-email-ta.omasab@gmail.com> X-Mailman-Approved-At: Wed, 13 Apr 2016 16:19:24 +0200 Cc: thomas.ab@samsung.com, alim.akhtar@samsung.com Subject: [U-Boot] [PATCH 2/9] pinctrl: Add pinctrl driver support for Exynos7420 SoC X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Thomas Abraham Add pinctrl driver support for Samsung's Exynos7420 SoC. The changes have been split into Exynos7420 specific and common Exynos specific portions so that this implementation is reusable on other Exynos SoCs as well. The Exynos pinctrl driver supports only device tree based pin configuration. The bindings used are similar to the ones used in the linux kernel. Cc: Masahiro Yamada Cc: Simon Glass Cc: Minkyu Kang Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Acked-by: Minkyu Kang --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/exynos/Kconfig | 10 ++ drivers/pinctrl/exynos/Makefile | 9 ++ drivers/pinctrl/exynos/pinctrl-exynos.c | 141 +++++++++++++++++++++++++++ drivers/pinctrl/exynos/pinctrl-exynos.h | 77 +++++++++++++++ drivers/pinctrl/exynos/pinctrl-exynos7420.c | 121 +++++++++++++++++++++++ 7 files changed, 360 insertions(+), 0 deletions(-) create mode 100644 drivers/pinctrl/exynos/Kconfig create mode 100644 drivers/pinctrl/exynos/Makefile create mode 100644 drivers/pinctrl/exynos/pinctrl-exynos.c create mode 100644 drivers/pinctrl/exynos/pinctrl-exynos.h create mode 100644 drivers/pinctrl/exynos/pinctrl-exynos7420.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 2a69bab..bdf8931 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -145,5 +145,6 @@ endif source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" +source "drivers/pinctrl/exynos/Kconfig" endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 37dc904..19beb04 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o +obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ diff --git a/drivers/pinctrl/exynos/Kconfig b/drivers/pinctrl/exynos/Kconfig new file mode 100644 index 0000000..84b6aaa --- /dev/null +++ b/drivers/pinctrl/exynos/Kconfig @@ -0,0 +1,10 @@ +config PINCTRL_EXYNOS + bool + +config PINCTRL_EXYNOS7420 + bool "Samsung Exynos7420 pinctrl driver" + depends on ARCH_EXYNOS && PINCTRL_FULL + select PINCTRL_EXYNOS + help + Support pin multiplexing and pin configuration control on + Samsung's Exynos7420 SoC. diff --git a/drivers/pinctrl/exynos/Makefile b/drivers/pinctrl/exynos/Makefile new file mode 100644 index 0000000..d9b941a --- /dev/null +++ b/drivers/pinctrl/exynos/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (C) 2016 Samsung Electronics +# Thomas Abraham +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o +obj-$(CONFIG_PINCTRL_EXYNOS7420) += pinctrl-exynos7420.o diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.c b/drivers/pinctrl/exynos/pinctrl-exynos.c new file mode 100644 index 0000000..a28405f --- /dev/null +++ b/drivers/pinctrl/exynos/pinctrl-exynos.c @@ -0,0 +1,141 @@ +/* + * Exynos pinctrl driver common code. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include "pinctrl-exynos.h" + +DECLARE_GLOBAL_DATA_PTR; + +/** + * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral. + * conf: soc specific pin configuration data array + * num_conf: number of configurations in the conf array. + * base: base address of the pin controller. + */ +void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf, + unsigned int num_conf, unsigned long base) +{ + unsigned int idx, val; + + for (idx = 0; idx < num_conf; idx++) { + val = readl(base + conf[idx].offset); + val &= ~(conf[idx].mask); + val |= conf[idx].value; + writel(val, base + conf[idx].offset); + } +} + +/* given a pin-name, return the address of pin config registers */ +static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin) +{ + struct exynos_pinctrl_priv *priv = dev_get_priv(dev); + const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl; + const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks; + u32 nr_banks = pin_ctrl->nr_banks, idx = 0; + char bank[10]; + + /* + * The format of the pin name is -. + * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number. + */ + while (pin_name[idx] != '-') { + bank[idx] = pin_name[idx]; + idx++; + } + bank[idx] = '\0'; + *pin = pin_name[++idx] - '0'; + + /* lookup the pin bank data using the pin bank name */ + for (idx = 0; idx < nr_banks; idx++) + if (!strcmp(bank, bank_data[idx].name)) + break; + + return priv->base + bank_data[idx].offset; +} + +/** + * exynos_pinctrl_set_state: configure a pin state. + * dev: the pinctrl device to be configured. + * config: the state to be configured. + */ +int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config) +{ + const void *fdt = gd->fdt_blob; + int node = config->of_offset; + unsigned int count, idx, pin_num, ret; + unsigned int pinfunc, pinpud, pindrv; + unsigned long reg, value; + const char *name; + + /* + * refer to the following document for the pinctrl bindings + * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt + */ + count = fdt_count_strings(fdt, node, "samsung,pins"); + if (count <= 0) + return -EINVAL; + + pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1); + pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1); + pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1); + + for (idx = 0; idx < count; idx++) { + ret = fdt_get_string_index(fdt, node, "samsung,pins", + idx, &name); + if (ret < 0) + continue; + reg = pin_to_bank_base(dev, name, &pin_num); + + if (pinfunc != -1) { + value = readl(reg + PIN_CON); + value &= ~(0xf << (pin_num << 2)); + value |= (pinfunc << (pin_num << 2)); + writel(value, reg + PIN_CON); + } + + if (pinpud != -1) { + value = readl(reg + PIN_PUD); + value &= ~(0x3 << (pin_num << 1)); + value |= (pinpud << (pin_num << 1)); + writel(value, reg + PIN_PUD); + } + + if (pindrv != -1) { + value = readl(reg + PIN_DRV); + value &= ~(0x3 << (pin_num << 1)); + value |= (pindrv << (pin_num << 1)); + writel(value, reg + PIN_DRV); + } + } + + return 0; +} + +int exynos_pinctrl_probe(struct udevice *dev) +{ + struct exynos_pinctrl_priv *priv; + fdt_addr_t base; + + priv = dev_get_priv(dev); + if (!priv) + return -EINVAL; + + base = dev_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = base; + priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) + + dev->req_seq; + + return 0; +} diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.h b/drivers/pinctrl/exynos/pinctrl-exynos.h new file mode 100644 index 0000000..abd582d --- /dev/null +++ b/drivers/pinctrl/exynos/pinctrl-exynos.h @@ -0,0 +1,77 @@ +/* + * Exynos pinctrl driver header. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINCTRL_EXYNOS_H_ +#define __PINCTRL_EXYNOS__H_ + +#define PIN_CON 0x00 /* Offset of pin function register */ +#define PIN_DAT 0x04 /* Offset of pin data register */ +#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */ +#define PIN_DRV 0x0C /* Offset of pin drive strength register */ + +/** + * struct samsung_pin_bank_data: represent a controller pin-bank data. + * @offset: starting offset of the pin-bank registers. + * @nr_pins: number of pins included in this bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct samsung_pin_bank_data { + u32 offset; + u8 nr_pins; + const char *name; +}; + +#define EXYNOS_PIN_BANK(pins, reg, id) \ + { \ + .offset = reg, \ + .nr_pins = pins, \ + .name = id \ + } + +/** + * struct samsung_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + */ +struct samsung_pin_ctrl { + const struct samsung_pin_bank_data *pin_banks; + u32 nr_banks; +}; + +/** + * struct exynos_pinctrl_priv: exynos pin controller driver private data + * @pin_ctrl: pin controller bank information. + * @base: base address of the pin controller instance. + * @num_banks: number of pin banks included in the pin controller. + */ +struct exynos_pinctrl_priv { + const struct samsung_pin_ctrl *pin_ctrl; + unsigned long base; + int num_banks; +}; + +/** + * struct exynos_pinctrl_config_data: configuration for a peripheral. + * @offset: offset of the config registers in the controller. + * @mask: value of the register to be masked with. + * @value: new value to be programmed. + */ +struct exynos_pinctrl_config_data { + const unsigned int offset; + const unsigned int mask; + const unsigned int value; +}; + + +void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf, + unsigned int num_conf, unsigned long base); +int exynos_pinctrl_set_state(struct udevice *dev, + struct udevice *config); +int exynos_pinctrl_probe(struct udevice *dev); + +#endif /* __PINCTRL_EXYNOS_H_ */ diff --git a/drivers/pinctrl/exynos/pinctrl-exynos7420.c b/drivers/pinctrl/exynos/pinctrl-exynos7420.c new file mode 100644 index 0000000..aca0677 --- /dev/null +++ b/drivers/pinctrl/exynos/pinctrl-exynos7420.c @@ -0,0 +1,120 @@ +/* + * Exynos7420 pinctrl driver. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-exynos.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define GPD1_OFFSET 0xc0 + +static struct exynos_pinctrl_config_data serial2_conf[] = { + { + .offset = GPD1_OFFSET + PIN_CON, + .mask = 0x00ff0000, + .value = 0x00220000, + }, { + .offset = GPD1_OFFSET + PIN_PUD, + .mask = 0x00000f00, + .value = 0x00000f00, + }, +}; + +static int exynos7420_pinctrl_request(struct udevice *dev, int peripheral, + int flags) +{ + struct exynos_pinctrl_priv *priv = dev_get_priv(dev); + unsigned long base = priv->base; + + switch (PERIPH_ID_UART2) { + case PERIPH_ID_UART2: + exynos_pinctrl_setup_peri(serial2_conf, + ARRAY_SIZE(serial2_conf), base); + break; + default: + return -ENODEV; + } + + return 0; +} + +static struct pinctrl_ops exynos7420_pinctrl_ops = { + .set_state = exynos_pinctrl_set_state, + .request = exynos7420_pinctrl_request, +}; + +/* pin banks of Exynos7420 pin-controller - BUS0 */ +static const struct samsung_pin_bank_data exynos7420_pin_banks0[] = { + EXYNOS_PIN_BANK(5, 0x000, "gpb0"), + EXYNOS_PIN_BANK(8, 0x020, "gpc0"), + EXYNOS_PIN_BANK(2, 0x040, "gpc1"), + EXYNOS_PIN_BANK(6, 0x060, "gpc2"), + EXYNOS_PIN_BANK(8, 0x080, "gpc3"), + EXYNOS_PIN_BANK(4, 0x0a0, "gpd0"), + EXYNOS_PIN_BANK(6, 0x0c0, "gpd1"), + EXYNOS_PIN_BANK(8, 0x0e0, "gpd2"), + EXYNOS_PIN_BANK(5, 0x100, "gpd4"), + EXYNOS_PIN_BANK(4, 0x120, "gpd5"), + EXYNOS_PIN_BANK(6, 0x140, "gpd6"), + EXYNOS_PIN_BANK(3, 0x160, "gpd7"), + EXYNOS_PIN_BANK(2, 0x180, "gpd8"), + EXYNOS_PIN_BANK(2, 0x1a0, "gpg0"), + EXYNOS_PIN_BANK(4, 0x1c0, "gpg3"), +}; + +/* pin banks of Exynos7420 pin-controller - FSYS0 */ +static const struct samsung_pin_bank_data exynos7420_pin_banks1[] = { + EXYNOS_PIN_BANK(7, 0x000, "gpr4"), +}; + +/* pin banks of Exynos7420 pin-controller - FSYS1 */ +static const struct samsung_pin_bank_data exynos7420_pin_banks2[] = { + EXYNOS_PIN_BANK(4, 0x000, "gpr0"), + EXYNOS_PIN_BANK(8, 0x020, "gpr1"), + EXYNOS_PIN_BANK(5, 0x040, "gpr2"), + EXYNOS_PIN_BANK(8, 0x060, "gpr3"), +}; + +const struct samsung_pin_ctrl exynos7420_pin_ctrl[] = { + { + /* pin-controller instance BUS0 data */ + .pin_banks = exynos7420_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos7420_pin_banks0), + }, { + /* pin-controller instance FSYS0 data */ + .pin_banks = exynos7420_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos7420_pin_banks1), + }, { + /* pin-controller instance FSYS1 data */ + .pin_banks = exynos7420_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos7420_pin_banks2), + }, +}; + +static const struct udevice_id exynos7420_pinctrl_ids[] = { + { .compatible = "samsung,exynos7420-pinctrl", + .data = (ulong)exynos7420_pin_ctrl }, + { } +}; + +U_BOOT_DRIVER(pinctrl_exynos7420) = { + .name = "pinctrl_exynos7420", + .id = UCLASS_PINCTRL, + .of_match = exynos7420_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv), + .ops = &exynos7420_pinctrl_ops, + .probe = exynos_pinctrl_probe, + .flags = DM_FLAG_PRE_RELOC +};