From patchwork Sat Jul 28 06:58:38 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 1251361 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 3AF5EE006E for ; Sat, 28 Jul 2012 07:07:01 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Sv12P-0007ic-9s; Sat, 28 Jul 2012 07:02:09 +0000 Received: from mail-pb0-f49.google.com ([209.85.160.49]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Sv0zu-0007di-7s for linux-arm-kernel@lists.infradead.org; Sat, 28 Jul 2012 06:59:34 +0000 Received: by mail-pb0-f49.google.com with SMTP id rq13so6832454pbb.36 for ; Fri, 27 Jul 2012 23:59:27 -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:x-mailer:in-reply-to:references; bh=gLcZMA+AYCQM2r+YdqdhryE1bHURb8iwAvsK7BKUSDk=; b=pAW67cLwEz6WbW4P/Q7Y51PNVD56K7qK8M+CBB8jh+gZCJu69XSd5leuLRsZCZkbGS Fd/hyTTSQVPzUnEtqOlxeB78pogy7e2kd1K3IrojCikxHVHEKi7Y5B8+ZkDArNYntArH lZME7n+mNw3ZeOllKgnYc+6ZD393w56DWDNcA510q2v5UxinxwNbKwWEKP1Sk7drt0VH PQx5Z0VcnWZMME9CAOMI02EKH/cSMAmoPzLuKA+mC7FX+l4rXWaj2mE/BRkl3t32ZlYL 0VySNw/Se63he+h9JLOzj+zSMUobo28YaXuJotulQgFutYhKt5dBNzoV1d1toxYCXqC1 emNA== Received: by 10.68.224.225 with SMTP id rf1mr19499420pbc.55.1343458767472; Fri, 27 Jul 2012 23:59:27 -0700 (PDT) Received: from localhost ([221.239.195.16]) by mx.google.com with ESMTPS id gh9sm3454357pbc.20.2012.07.27.23.59.06 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 27 Jul 2012 23:59:10 -0700 (PDT) From: Haojian Zhuang To: linux-arm-kernel@lists.infradead.org, grant.likely@secretlab.ca, linus.walleij@stericsson.com, arnd@arndb.de Subject: [PATCH 2/6] pinctrl: add pinconf support in pxa3xx Date: Sat, 28 Jul 2012 14:58:38 +0800 Message-Id: <1343458722-17127-3-git-send-email-haojian.zhuang@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1343458722-17127-1-git-send-email-haojian.zhuang@gmail.com> References: <1343458722-17127-1-git-send-email-haojian.zhuang@gmail.com> X-Spam-Note: CRM114 invocation failed X-Spam-Note: SpamAssassin invocation failed Cc: Haojian Zhuang X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Signed-off-by: Haojian Zhuang Acked-by: Linus Walleij --- drivers/pinctrl/pinctrl-pxa3xx.c | 189 ++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-pxa3xx.h | 17 ++++ 2 files changed, 206 insertions(+) diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c index f14cd6b..cae74db 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.c +++ b/drivers/pinctrl/pinctrl-pxa3xx.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "pinctrl-pxa3xx.h" static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = { @@ -168,6 +170,192 @@ static struct pinmux_ops pxa3xx_pmx_ops = { .gpio_request_enable = pxa3xx_pmx_request_gpio, }; +static int pxa3xx_pinconf_get(struct pinctrl_dev *pctrldev, + unsigned pin, unsigned long *config) +{ + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + unsigned int data, mask; + int mfpr; + + mfpr = info->mfp[pin].mfpr; + data = readl_relaxed(info->virt_base + mfpr); + + *config = 0; + mask = PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_UP; + if ((data & mask) == mask) + *config |= PXA3XX_PINCONF_PULL_UP; + mask = PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_DOWN; + if ((data & mask) == mask) + *config |= PXA3XX_PINCONF_PULL_DOWN; + mask = info->ds_mask; + if (data & mask) { + *config |= PXA3XX_PINCONF_DRIVE_STRENGTH; + *config |= ((data & mask) >> info->ds_shift) + << PXA3XX_PINCONF_DS_SHIFT; + } + mask = info->slp_mask; + if (data & mask) { + if (data & info->slp_input_low) + *config |= PXA3XX_PINCONF_LOWPOWER_PULL_DOWN; + if (data & info->slp_input_high) + *config |= PXA3XX_PINCONF_LOWPOWER_PULL_UP; + if (data & info->slp_output_low) + *config |= PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW; + if (data & info->slp_output_high) + *config |= PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH; + if (data & info->slp_float) + *config |= PXA3XX_PINCONF_LOWPOWER_FLOAT; + } else + *config |= PXA3XX_PINCONF_LOWPOWER_ZERO; + return 0; +} + +static int pxa3xx_pinconf_set(struct pinctrl_dev *pctrldev, + unsigned pin, unsigned long config) +{ + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + unsigned int data; + int mfpr; + + mfpr = info->mfp[pin].mfpr; + data = readl_relaxed(info->virt_base + mfpr); + switch (config & PXA3XX_PINCONF_MASK) { + case PXA3XX_PINCONF_PULL_DOWN: + data |= PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_DOWN; + break; + case PXA3XX_PINCONF_PULL_UP: + data |= PXA3XX_MFPR_PULL_SEL | PXA3XX_MFPR_PULL_UP; + break; + case PXA3XX_PINCONF_DRIVE_STRENGTH: + data &= ~info->ds_mask; + data |= (config >> PXA3XX_PINCONF_DS_SHIFT) << info->ds_shift; + break; + case PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH: + data &= ~info->slp_mask; + data |= info->slp_output_high; + break; + case PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW: + data &= ~info->slp_mask; + data |= info->slp_output_low; + break; + case PXA3XX_PINCONF_LOWPOWER_PULL_UP: + data &= ~info->slp_mask; + data |= info->slp_input_high; + break; + case PXA3XX_PINCONF_LOWPOWER_PULL_DOWN: + data &= ~info->slp_mask; + data |= info->slp_input_low; + break; + case PXA3XX_PINCONF_LOWPOWER_FLOAT: + data &= ~info->slp_mask; + data |= info->slp_float; + break; + case PXA3XX_PINCONF_LOWPOWER_ZERO: + data &= ~info->slp_mask; + break; + default: + return -ENOTSUPP; + } + writel_relaxed(data, info->virt_base + mfpr); + return 0; +} + +static int pxa3xx_pinconf_group_get(struct pinctrl_dev *pctrldev, + unsigned group, unsigned long *config) +{ + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + const unsigned *pins = info->grps[group].pins; + int npins, i; + unsigned long conf, match = 0; + + npins = info->grps[group].npins; + for (i = 0; i < npins; i++) { + pxa3xx_pinconf_get(pctrldev, pins[i], &conf); + if (!match) + match = conf; + else if (match != conf) { + *config = conf; + return -EINVAL; + } + } + *config = conf; + return 0; +} + +static int pxa3xx_pinconf_group_set(struct pinctrl_dev *pctrldev, + unsigned group, unsigned long config) +{ + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + const unsigned *pins = info->grps[group].pins; + int npins, i; + + npins = info->grps[group].npins; + for (i = 0; i < npins; i++) + pxa3xx_pinconf_set(pctrldev, pins[i], config); + return 0; +} + +static void pxa3xx_pinconf_dbg_show(struct pinctrl_dev *pctrldev, + struct seq_file *s, unsigned offset) +{ + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + unsigned long config; + char buf[80]; + int i = 0, mfpr; + + pxa3xx_pinconf_get(pctrldev, offset, &config); + memset(buf, 0, 80); + if (config & PXA3XX_PINCONF_PULL_UP) + i += sprintf(buf + i, "PULL UP, "); + if (config & PXA3XX_PINCONF_PULL_DOWN) + i += sprintf(buf + i, "PULL DOWN, "); + if (config & PXA3XX_PINCONF_DRIVE_STRENGTH) + i += sprintf(buf + i, "DRIVE STRENGTH (%ld), ", + config >> PXA3XX_PINCONF_DS_SHIFT); + if (config & PXA3XX_PINCONF_LOWPOWER_PULL_UP) + i += sprintf(buf + i, "LP PULL UP, "); + if (config & PXA3XX_PINCONF_LOWPOWER_PULL_DOWN) + i += sprintf(buf + i, "LP PULL DOWN, "); + if (config & PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH) + i += sprintf(buf + i, "LP DRIVE HIGH, "); + if (config & PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW) + i += sprintf(buf + i, "LP DRIVE LOW, "); + if (config & PXA3XX_PINCONF_LOWPOWER_FLOAT) + i += sprintf(buf + i, "LP FLOAT, "); + if (config & PXA3XX_PINCONF_LOWPOWER_ZERO) + i += sprintf(buf + i, "LP ZERO, "); + seq_printf(s, "%s\n", buf); + + mfpr = info->mfp[offset].mfpr; + seq_printf(s, "reg[0x%x]:0x%x\n", info->phy_base + mfpr, + readl_relaxed(info->virt_base + mfpr)); +} + +static void pxa3xx_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev, + struct seq_file *s, unsigned group) +{ + struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + const unsigned *pins = info->grps[group].pins; + int ret; + unsigned long config; + + ret = pxa3xx_pinconf_group_get(pctrldev, group, &config); + if (ret < 0) { + seq_printf(s, "group config is not consistent\n"); + return; + } + pxa3xx_pinconf_dbg_show(pctrldev, s, pins[0]); +} + +static struct pinconf_ops pxa3xx_pinconf_ops = { + .pin_config_get = pxa3xx_pinconf_get, + .pin_config_set = pxa3xx_pinconf_set, + .pin_config_group_get = pxa3xx_pinconf_group_get, + .pin_config_group_set = pxa3xx_pinconf_group_set, + .pin_config_dbg_show = pxa3xx_pinconf_dbg_show, + .pin_config_group_dbg_show = pxa3xx_pinconf_group_dbg_show, +}; + int pxa3xx_pinctrl_register(struct platform_device *pdev, struct pxa3xx_pinmux_info *info) { @@ -182,6 +370,7 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev, desc->npins = info->num_pads; desc->pctlops = &pxa3xx_pctrl_ops; desc->pmxops = &pxa3xx_pmx_ops; + desc->confops = &pxa3xx_pinconf_ops; info->dev = &pdev->dev; pxa3xx_pinctrl_gpio_range.npins = info->num_gpio; diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h index 8135744..fdcf805 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.h +++ b/drivers/pinctrl/pinctrl-pxa3xx.h @@ -12,6 +12,7 @@ */ #ifndef __PINCTRL_PXA3XX_H +#define __PINCTRL_PXA3XX_H #include #include @@ -23,6 +24,22 @@ #define PXA3xx_MAX_MUX 8 #define MFPR_FUNC_MASK 0x7 +#define PXA3XX_PINCONF_PULL_UP (1 << 0) +#define PXA3XX_PINCONF_PULL_DOWN (1 << 1) +#define PXA3XX_PINCONF_DRIVE_STRENGTH (1 << 2) +#define PXA3XX_PINCONF_LOWPOWER_PULL_UP (1 << 3) +#define PXA3XX_PINCONF_LOWPOWER_PULL_DOWN (1 << 4) +#define PXA3XX_PINCONF_LOWPOWER_DRIVE_HIGH (1 << 5) +#define PXA3XX_PINCONF_LOWPOWER_DRIVE_LOW (1 << 6) +#define PXA3XX_PINCONF_LOWPOWER_FLOAT (1 << 7) +#define PXA3XX_PINCONF_LOWPOWER_ZERO (1 << 8) /* lowpower bits: 0 */ +#define PXA3XX_PINCONF_MASK 0xffff +#define PXA3XX_PINCONF_DS_SHIFT 16 + +#define PXA3XX_MFPR_PULL_SEL (1 << 15) +#define PXA3XX_MFPR_PULL_UP (1 << 14) +#define PXA3XX_MFPR_PULL_DOWN (1 << 13) + enum pxa_cpu_type { PINCTRL_INVALID = 0, PINCTRL_PXA300,