From patchwork Sun Jun 25 15:55:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Beniamino Galvani X-Patchwork-Id: 9808229 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 784B66038C for ; Sun, 25 Jun 2017 15:59:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 65F5327FC0 for ; Sun, 25 Jun 2017 15:59:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5A51828675; Sun, 25 Jun 2017 15:59:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9F80A28662 for ; Sun, 25 Jun 2017 15:59:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=mb5E/10/Pgguhvq2Nu6GMOtKr2fx5todF2m1RFc0Uv4=; b=Wy59RceDj94FPwv5mGTUQ7ic1i ct4cbnfyDawv4WajsBAPZ+Uq8iVUBaTgiKJssugHnZh1nIO3vpNoHcC4AFMS9Bgl2Y6Ei5XSs/yKP Is+5OCcv9rSBsNOAGt7Ra6/qCQcUx+x9H0beBgUtfFRI0iQEfNvmmAkSE75ANu9JBGbXGLnawzqzJ cWj35HOnKJ0e5RyZpdmwWEf65C2rtInUlAmGeg7itoYhaTGQuzN740v8QX8A+49KLewLykfMfhdsi h1u/JgVoxcMPlGzSYHffcypgaAK1ThfRYrrX/5hZlqb+EeOOfxz2tNy4SEocIS5klqyeC+E9s9Lp7 oy0GNEzw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dP9wN-0003ZG-MY; Sun, 25 Jun 2017 15:59:11 +0000 Received: from mail-wr0-x243.google.com ([2a00:1450:400c:c0c::243]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dP9wJ-0003UZ-G9 for linux-amlogic@lists.infradead.org; Sun, 25 Jun 2017 15:59:09 +0000 Received: by mail-wr0-x243.google.com with SMTP id z45so25144820wrb.2 for ; Sun, 25 Jun 2017 08:58:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=g9aUNPojl9KL8op+QAAJWYuIKVQErhXDwEQDaAeFncg=; b=WHAoS8wGBSjTx1MGoVeFsKjabk4vb9AsfDQLYw3FtoV4HJAex1Ae04DT9ahVtPZwFj Wj7UZEog9SlBvM5ZZbRTC4Danra6mQ5lkgYkr9XGDz/5xBube9Gb1rpaHfiK/kAc8+Kr IZ/7SbzpG8IwyLgW0gG8QoZ/5MMp4jp0LjI+HScpJ4807siw8sWTBNSu3sLjCZ5slwEW crtpgp/LWIuF9/1x7OhesCHZS0AzqMaYWGEVtkr3VcYEVyq5OfSALd9fhfhFX0jW7TIX 2R1Cji4lMvobECbwQQl+s4+y52R9j1PlCkViCnqxvxq4OURErXUMR2VBNKeGpTVfeZ1w HwvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=g9aUNPojl9KL8op+QAAJWYuIKVQErhXDwEQDaAeFncg=; b=tE9bItUW3B94icRBUjvd9ZgM//OYzqXbahZy3VjFXofFXWzKqlqj6+51Va9pZojCij hqTcb4SUZx0Y2KjrP8Fhg5UFkNzdO7fJnYpBf4EomywAmI+rJGMXN6DMWgr4xwPm4dk+ cXUz1VQfSe8Flt7LxplbQFsVH+y9/tcLthbKE73ylrd7imSR5q9sJY5LPxD4C4HSjBXv i2qS6dk2kxWjDUzkGtXHozdZAhQ6S5EcLchN9YPrYOV55iuyr6ncw28vS6x45sct+JQl zgRnqG1nnyJbRog2VaGJVUnH8e2LC4vF5xXIM84HSZXjDgtEyY6LnBWa7oSHynhDEf+z MEWw== X-Gm-Message-State: AKS2vOxC2yp0O9Lr/vgMBF68QWyeBuDIt99mw3cTVKucEAkM0Vpbq4sH 8jOKy94szbLqqQ== X-Received: by 10.223.130.134 with SMTP id 6mr11985107wrc.16.1498406325853; Sun, 25 Jun 2017 08:58:45 -0700 (PDT) Received: from sark.fritz.box ([95.236.112.217]) by smtp.gmail.com with ESMTPSA id k12sm14027989wrc.10.2017.06.25.08.58.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 25 Jun 2017 08:58:45 -0700 (PDT) From: Beniamino Galvani To: u-boot@lists.denx.de Subject: [PATCH 2/3] pinctrl: meson: add GPIO support Date: Sun, 25 Jun 2017 17:55:10 +0200 Message-Id: <20170625155511.28447-3-b.galvani@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170625155511.28447-1-b.galvani@gmail.com> References: <20170625155511.28447-1-b.galvani@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170625_085907_851079_BE2B7E28 X-CRM114-Status: GOOD ( 19.58 ) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Beniamino Galvani , Tom Rini , Simon Glass , linux-amlogic@lists.infradead.org, Albert Aribaud MIME-Version: 1.0 Sender: "linux-amlogic" Errors-To: linux-amlogic-bounces+patchwork-linux-amlogic=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This commit adds GPIO support to the Amlogic Meson pin controller driver, based on code from Linux kernel. Signed-off-by: Beniamino Galvani Reviewed-by: Simon Glass --- drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 21 ++++ drivers/pinctrl/meson/pinctrl-meson.c | 167 ++++++++++++++++++++++++++++- drivers/pinctrl/meson/pinctrl-meson.h | 63 +++++++++++ 3 files changed, 249 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c index 2fa840c..87c9912 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c @@ -391,14 +391,33 @@ static struct meson_pmx_func meson_gxbb_aobus_functions[] = { FUNCTION(i2c_slave_ao), }; +static struct meson_bank meson_gxbb_periphs_banks[] = { + /* name first last pullen pull dir out in */ + BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), + BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), + BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), + BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 1, 20, 1, 20, 3, 20, 4, 20, 5, 20), + BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), + BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 2, 20, 2, 20, 6, 20, 7, 20, 8, 20), + BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), + BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 3, 28, 3, 28, 9, 28, 10, 28, 11, 28), +}; + +static struct meson_bank meson_gxbb_aobus_banks[] = { + /* name first last pullen pull dir out in */ + BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0), +}; + struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = { .name = "periphs-banks", .pin_base = 14, .groups = meson_gxbb_periphs_groups, .funcs = meson_gxbb_periphs_functions, + .banks = meson_gxbb_periphs_banks, .num_pins = 120, .num_groups = ARRAY_SIZE(meson_gxbb_periphs_groups), .num_funcs = ARRAY_SIZE(meson_gxbb_periphs_functions), + .num_banks = ARRAY_SIZE(meson_gxbb_periphs_banks), }; struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = { @@ -406,9 +425,11 @@ struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = { .pin_base = 0, .groups = meson_gxbb_aobus_groups, .funcs = meson_gxbb_aobus_functions, + .banks = meson_gxbb_aobus_banks, .num_pins = 14, .num_groups = ARRAY_SIZE(meson_gxbb_aobus_groups), .num_funcs = ARRAY_SIZE(meson_gxbb_aobus_functions), + .num_banks = ARRAY_SIZE(meson_gxbb_aobus_banks), }; static const struct udevice_id meson_gxbb_pinctrl_match[] = { diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 6281f52..0ac1dc6 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -6,11 +6,14 @@ #include #include +#include +#include #include #include #include #include #include +#include #include "pinctrl-meson.h" @@ -135,12 +138,152 @@ static fdt_addr_t parse_address(int offset, const char *name, int na, int ns) return fdt_translate_address((void *)gd->fdt_blob, offset, reg); } +static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset, + enum meson_reg_type reg_type, + unsigned int *reg, unsigned int *bit) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + struct meson_bank *bank = NULL; + struct meson_reg_desc *desc; + unsigned int pin; + int i; + + pin = priv->data->pin_base + offset; + + for (i = 0; i < priv->data->num_banks; i++) { + if (pin >= priv->data->banks[i].first && + pin <= priv->data->banks[i].last) { + bank = &priv->data->banks[i]; + break; + } + } + + if (!bank) + return -EINVAL; + + desc = &bank->regs[reg_type]; + *reg = desc->reg * 4; + *bit = desc->bit + pin - bank->first; + + return 0; +} + +static int meson_gpio_get(struct udevice *dev, unsigned int offset) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_IN, ®, &bit); + if (ret) + return ret; + + return !!(readl(priv->reg_gpio + reg) & BIT(bit)); +} + +static int meson_gpio_set(struct udevice *dev, unsigned int offset, int value) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0); + + return 0; +} + +static int meson_gpio_get_direction(struct udevice *dev, unsigned int offset) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit, val; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + if (ret) + return ret; + + val = readl(priv->reg_gpio + reg); + + return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT; +} + +static int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 1); + + return 0; +} + +static int meson_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 0); + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0); + + return 0; +} + +static int meson_gpio_probe(struct udevice *dev) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(dev); + uc_priv->bank_name = priv->data->name; + uc_priv->gpio_count = priv->data->num_pins; + + return 0; +} + +static const struct dm_gpio_ops meson_gpio_ops = { + .set_value = meson_gpio_set, + .get_value = meson_gpio_get, + .get_function = meson_gpio_get_direction, + .direction_input = meson_gpio_direction_input, + .direction_output = meson_gpio_direction_output, +}; + +static struct driver meson_gpio_driver = { + .name = "meson-gpio", + .id = UCLASS_GPIO, + .probe = meson_gpio_probe, + .ops = &meson_gpio_ops, +}; + int meson_pinctrl_probe(struct udevice *dev) { struct meson_pinctrl *priv = dev_get_priv(dev); + struct uclass_driver *drv; + struct udevice *gpio_dev; fdt_addr_t addr; int node, gpio = -1, len; int na, ns; + char *name; na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent)); if (na < 1) { @@ -168,12 +311,32 @@ int meson_pinctrl_probe(struct udevice *dev) addr = parse_address(gpio, "mux", na, ns); if (addr == FDT_ADDR_T_NONE) { - debug("mux not found\n"); + debug("mux address not found\n"); return -EINVAL; } - priv->reg_mux = (void __iomem *)addr; + + addr = parse_address(gpio, "gpio", na, ns); + if (addr == FDT_ADDR_T_NONE) { + debug("gpio address not found\n"); + return -EINVAL; + } + priv->reg_gpio = (void __iomem *)addr; priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev); + /* Lookup GPIO driver */ + drv = lists_uclass_lookup(UCLASS_GPIO); + if (!drv) { + puts("Cannot find GPIO driver\n"); + return -ENOENT; + } + + name = calloc(1, 32); + sprintf(name, "meson-gpio"); + + /* Create child device UCLASS_GPIO and bind it */ + device_bind(dev, &meson_gpio_driver, name, NULL, gpio, &gpio_dev); + dev_set_of_offset(gpio_dev, gpio); + return 0; } diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index 4127a60..90d2369 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -28,15 +28,64 @@ struct meson_pinctrl_data { const char *name; struct meson_pmx_group *groups; struct meson_pmx_func *funcs; + struct meson_bank *banks; unsigned int pin_base; unsigned int num_pins; unsigned int num_groups; unsigned int num_funcs; + unsigned int num_banks; }; struct meson_pinctrl { struct meson_pinctrl_data *data; void __iomem *reg_mux; + void __iomem *reg_gpio; +}; + +/** + * struct meson_reg_desc - a register descriptor + * + * @reg: register offset in the regmap + * @bit: bit index in register + * + * The structure describes the information needed to control pull, + * pull-enable, direction, etc. for a single pin + */ +struct meson_reg_desc { + unsigned int reg; + unsigned int bit; +}; + +/** + * enum meson_reg_type - type of registers encoded in @meson_reg_desc + */ +enum meson_reg_type { + REG_PULLEN, + REG_PULL, + REG_DIR, + REG_OUT, + REG_IN, + NUM_REG, +}; + +/** + * struct meson bank + * + * @name: bank name + * @first: first pin of the bank + * @last: last pin of the bank + * @regs: array of register descriptors + * + * A bank represents a set of pins controlled by a contiguous set of + * bits in the domain registers. The structure specifies which bits in + * the regmap control the different functionalities. Each member of + * the @regs array refers to the first pin of the bank. + */ +struct meson_bank { + const char *name; + unsigned int first; + unsigned int last; + struct meson_reg_desc regs[NUM_REG]; }; #define PIN(x, b) (b + x) @@ -65,6 +114,20 @@ struct meson_pinctrl { .num_groups = ARRAY_SIZE(fn ## _groups), \ } +#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ + { \ + .name = n, \ + .first = f, \ + .last = l, \ + .regs = { \ + [REG_PULLEN] = { per, peb }, \ + [REG_PULL] = { pr, pb }, \ + [REG_DIR] = { dr, db }, \ + [REG_OUT] = { or, ob }, \ + [REG_IN] = { ir, ib }, \ + }, \ + } + #define MESON_PIN(x, b) PINCTRL_PIN(PIN(x, b), #x) extern const struct pinctrl_ops meson_pinctrl_ops;