forked from Minki/linux
Merge branch 'pinctrl-tegra-for-next-diet' into for-next
This commit is contained in:
commit
a6c3b33f02
@ -7,6 +7,8 @@ config ARCH_TEGRA_2x_SOC
|
||||
select CPU_V7
|
||||
select ARM_GIC
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select PINCTRL
|
||||
select PINCTRL_TEGRA20
|
||||
select USB_ARCH_HAS_EHCI if USB_SUPPORT
|
||||
select USB_ULPI if USB_SUPPORT
|
||||
select USB_ULPI_VIEWPORT if USB_SUPPORT
|
||||
@ -19,6 +21,8 @@ config ARCH_TEGRA_3x_SOC
|
||||
select CPU_V7
|
||||
select ARM_GIC
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select PINCTRL
|
||||
select PINCTRL_TEGRA30
|
||||
select USB_ARCH_HAS_EHCI if USB_SUPPORT
|
||||
select USB_ULPI if USB_SUPPORT
|
||||
select USB_ULPI_VIEWPORT if USB_SUPPORT
|
||||
|
63
arch/arm/mach-tegra/include/mach/pinconf-tegra.h
Normal file
63
arch/arm/mach-tegra/include/mach/pinconf-tegra.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* pinctrl configuration definitions for the NVIDIA Tegra pinmux
|
||||
*
|
||||
* Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef __PINCONF_TEGRA_H__
|
||||
#define __PINCONF_TEGRA_H__
|
||||
|
||||
enum tegra_pinconf_param {
|
||||
/* argument: tegra_pinconf_pull */
|
||||
TEGRA_PINCONF_PARAM_PULL,
|
||||
/* argument: tegra_pinconf_tristate */
|
||||
TEGRA_PINCONF_PARAM_TRISTATE,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_ENABLE_INPUT,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_OPEN_DRAIN,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_LOCK,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_IORESET,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_SCHMITT,
|
||||
/* argument: Boolean */
|
||||
TEGRA_PINCONF_PARAM_LOW_POWER_MODE,
|
||||
/* argument: Integer, range is HW-dependant */
|
||||
TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH,
|
||||
/* argument: Integer, range is HW-dependant */
|
||||
TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH,
|
||||
/* argument: Integer, range is HW-dependant */
|
||||
TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING,
|
||||
/* argument: Integer, range is HW-dependant */
|
||||
TEGRA_PINCONF_PARAM_SLEW_RATE_RISING,
|
||||
};
|
||||
|
||||
enum tegra_pinconf_pull {
|
||||
TEGRA_PINCONFIG_PULL_NONE,
|
||||
TEGRA_PINCONFIG_PULL_DOWN,
|
||||
TEGRA_PINCONFIG_PULL_UP,
|
||||
};
|
||||
|
||||
enum tegra_pinconf_tristate {
|
||||
TEGRA_PINCONFIG_DRIVEN,
|
||||
TEGRA_PINCONFIG_TRISTATE,
|
||||
};
|
||||
|
||||
#define TEGRA_PINCONF_PACK(_param_, _arg_) ((_param_) << 16 | (_arg_))
|
||||
#define TEGRA_PINCONF_UNPACK_PARAM(_conf_) ((_conf_) >> 16)
|
||||
#define TEGRA_PINCONF_UNPACK_ARG(_conf_) ((_conf_) & 0xffff)
|
||||
|
||||
#endif
|
@ -50,6 +50,21 @@ config PINCTRL_SIRF
|
||||
depends on ARCH_PRIMA2
|
||||
select PINMUX
|
||||
|
||||
config PINCTRL_TEGRA
|
||||
bool
|
||||
|
||||
config PINCTRL_TEGRA20
|
||||
bool
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select PINCTRL_TEGRA
|
||||
|
||||
config PINCTRL_TEGRA30
|
||||
bool
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select PINCTRL_TEGRA
|
||||
|
||||
config PINCTRL_U300
|
||||
bool "U300 pin controller driver"
|
||||
depends on ARCH_U300
|
||||
|
@ -10,5 +10,8 @@ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
|
||||
obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
|
||||
obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o
|
||||
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
|
||||
obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o
|
||||
obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
|
||||
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
|
||||
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
|
||||
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
|
||||
|
559
drivers/pinctrl/pinctrl-tegra.c
Normal file
559
drivers/pinctrl/pinctrl-tegra.c
Normal file
@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Driver for the NVIDIA Tegra pinmux
|
||||
*
|
||||
* Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Derived from code:
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (C) 2010 NVIDIA Corporation
|
||||
* Copyright (C) 2009-2011 ST-Ericsson AB
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
|
||||
#include <mach/pinconf-tegra.h>
|
||||
|
||||
#include "pinctrl-tegra.h"
|
||||
|
||||
#define DRIVER_NAME "tegra-pinmux-disabled"
|
||||
|
||||
struct tegra_pmx {
|
||||
struct device *dev;
|
||||
struct pinctrl_dev *pctl;
|
||||
|
||||
const struct tegra_pinctrl_soc_data *soc;
|
||||
|
||||
int nbanks;
|
||||
void __iomem **regs;
|
||||
};
|
||||
|
||||
static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
|
||||
{
|
||||
return readl(pmx->regs[bank] + reg);
|
||||
}
|
||||
|
||||
static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
|
||||
{
|
||||
writel(val, pmx->regs[bank] + reg);
|
||||
}
|
||||
|
||||
static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
|
||||
unsigned group)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned group)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return NULL;
|
||||
|
||||
return pmx->soc->groups[group].name;
|
||||
}
|
||||
|
||||
static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
unsigned group,
|
||||
const unsigned **pins,
|
||||
unsigned *num_pins)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
|
||||
*pins = pmx->soc->groups[group].pins;
|
||||
*num_pins = pmx->soc->groups[group].npins;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s,
|
||||
unsigned offset)
|
||||
{
|
||||
seq_printf(s, " " DRIVER_NAME);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops tegra_pinctrl_ops = {
|
||||
.list_groups = tegra_pinctrl_list_groups,
|
||||
.get_group_name = tegra_pinctrl_get_group_name,
|
||||
.get_group_pins = tegra_pinctrl_get_group_pins,
|
||||
.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
|
||||
};
|
||||
|
||||
static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
|
||||
unsigned function)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
|
||||
unsigned function)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return NULL;
|
||||
|
||||
return pmx->soc->functions[function].name;
|
||||
}
|
||||
|
||||
static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
|
||||
unsigned function,
|
||||
const char * const **groups,
|
||||
unsigned * const num_groups)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return -EINVAL;
|
||||
|
||||
*groups = pmx->soc->functions[function].groups;
|
||||
*num_groups = pmx->soc->functions[function].ngroups;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
|
||||
unsigned group)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
const struct tegra_pingroup *g;
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
if (g->mux_reg < 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(g->funcs); i++) {
|
||||
if (g->funcs[i] == function)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(g->funcs))
|
||||
return -EINVAL;
|
||||
|
||||
val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
|
||||
val &= ~(0x3 << g->mux_bit);
|
||||
val |= i << g->mux_bit;
|
||||
pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
|
||||
unsigned function, unsigned group)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
const struct tegra_pingroup *g;
|
||||
u32 val;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
if (g->mux_reg < 0)
|
||||
return;
|
||||
|
||||
val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
|
||||
val &= ~(0x3 << g->mux_bit);
|
||||
val |= g->func_safe << g->mux_bit;
|
||||
pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
|
||||
}
|
||||
|
||||
static struct pinmux_ops tegra_pinmux_ops = {
|
||||
.list_functions = tegra_pinctrl_list_funcs,
|
||||
.get_function_name = tegra_pinctrl_get_func_name,
|
||||
.get_function_groups = tegra_pinctrl_get_func_groups,
|
||||
.enable = tegra_pinctrl_enable,
|
||||
.disable = tegra_pinctrl_disable,
|
||||
};
|
||||
|
||||
static int tegra_pinconf_reg(struct tegra_pmx *pmx,
|
||||
const struct tegra_pingroup *g,
|
||||
enum tegra_pinconf_param param,
|
||||
s8 *bank, s16 *reg, s8 *bit, s8 *width)
|
||||
{
|
||||
switch (param) {
|
||||
case TEGRA_PINCONF_PARAM_PULL:
|
||||
*bank = g->pupd_bank;
|
||||
*reg = g->pupd_reg;
|
||||
*bit = g->pupd_bit;
|
||||
*width = 2;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_TRISTATE:
|
||||
*bank = g->tri_bank;
|
||||
*reg = g->tri_reg;
|
||||
*bit = g->tri_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_ENABLE_INPUT:
|
||||
*bank = g->einput_bank;
|
||||
*reg = g->einput_reg;
|
||||
*bit = g->einput_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_OPEN_DRAIN:
|
||||
*bank = g->odrain_bank;
|
||||
*reg = g->odrain_reg;
|
||||
*bit = g->odrain_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_LOCK:
|
||||
*bank = g->lock_bank;
|
||||
*reg = g->lock_reg;
|
||||
*bit = g->lock_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_IORESET:
|
||||
*bank = g->ioreset_bank;
|
||||
*reg = g->ioreset_reg;
|
||||
*bit = g->ioreset_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->hsm_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_SCHMITT:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->schmitt_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_LOW_POWER_MODE:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->lpmd_bit;
|
||||
*width = 1;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->drvdn_bit;
|
||||
*width = g->drvdn_width;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->drvup_bit;
|
||||
*width = g->drvup_width;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->slwf_bit;
|
||||
*width = g->slwf_width;
|
||||
break;
|
||||
case TEGRA_PINCONF_PARAM_SLEW_RATE_RISING:
|
||||
*bank = g->drv_bank;
|
||||
*reg = g->drv_reg;
|
||||
*bit = g->slwr_bit;
|
||||
*width = g->slwr_width;
|
||||
break;
|
||||
default:
|
||||
dev_err(pmx->dev, "Invalid config param %04x\n", param);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (*reg < 0) {
|
||||
dev_err(pmx->dev,
|
||||
"Config param %04x not supported on group %s\n",
|
||||
param, g->name);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
|
||||
unsigned pin, unsigned long *config)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
|
||||
unsigned pin, unsigned long config)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
|
||||
unsigned group, unsigned long *config)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(*config);
|
||||
u16 arg;
|
||||
const struct tegra_pingroup *g;
|
||||
int ret;
|
||||
s8 bank, bit, width;
|
||||
s16 reg;
|
||||
u32 val, mask;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = pmx_readl(pmx, bank, reg);
|
||||
mask = (1 << width) - 1;
|
||||
arg = (val >> bit) & mask;
|
||||
|
||||
*config = TEGRA_PINCONF_PACK(param, arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
|
||||
unsigned group, unsigned long config)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
|
||||
u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
|
||||
const struct tegra_pingroup *g;
|
||||
int ret;
|
||||
s8 bank, bit, width;
|
||||
s16 reg;
|
||||
u32 val, mask;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = pmx_readl(pmx, bank, reg);
|
||||
|
||||
/* LOCK can't be cleared */
|
||||
if (param == TEGRA_PINCONF_PARAM_LOCK) {
|
||||
if ((val & BIT(bit)) && !arg)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Special-case Boolean values; allow any non-zero as true */
|
||||
if (width == 1)
|
||||
arg = !!arg;
|
||||
|
||||
/* Range-check user-supplied value */
|
||||
mask = (1 << width) - 1;
|
||||
if (arg & ~mask)
|
||||
return -EINVAL;
|
||||
|
||||
/* Update register */
|
||||
val &= ~(mask << bit);
|
||||
val |= arg << bit;
|
||||
pmx_writel(pmx, val, bank, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned offset)
|
||||
{
|
||||
}
|
||||
|
||||
static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned selector)
|
||||
{
|
||||
}
|
||||
|
||||
struct pinconf_ops tegra_pinconf_ops = {
|
||||
.pin_config_get = tegra_pinconf_get,
|
||||
.pin_config_set = tegra_pinconf_set,
|
||||
.pin_config_group_get = tegra_pinconf_group_get,
|
||||
.pin_config_group_set = tegra_pinconf_group_set,
|
||||
.pin_config_dbg_show = tegra_pinconf_dbg_show,
|
||||
.pin_config_group_dbg_show = tegra_pinconf_group_dbg_show,
|
||||
};
|
||||
|
||||
static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
|
||||
.name = "Tegra GPIOs",
|
||||
.id = 0,
|
||||
.base = 0,
|
||||
};
|
||||
|
||||
static struct pinctrl_desc tegra_pinctrl_desc = {
|
||||
.name = DRIVER_NAME,
|
||||
.pctlops = &tegra_pinctrl_ops,
|
||||
.pmxops = &tegra_pinmux_ops,
|
||||
.confops = &tegra_pinconf_ops,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = {
|
||||
#ifdef CONFIG_PINCTRL_TEGRA20
|
||||
{
|
||||
.compatible = "nvidia,tegra20-pinmux-disabled",
|
||||
.data = tegra20_pinctrl_init,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_TEGRA30
|
||||
{
|
||||
.compatible = "nvidia,tegra30-pinmux-disabled",
|
||||
.data = tegra30_pinctrl_init,
|
||||
},
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
||||
static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
tegra_pinctrl_soc_initf initf = NULL;
|
||||
struct tegra_pmx *pmx;
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
match = of_match_device(tegra_pinctrl_of_match, &pdev->dev);
|
||||
if (match)
|
||||
initf = (tegra_pinctrl_soc_initf)match->data;
|
||||
#ifdef CONFIG_PINCTRL_TEGRA20
|
||||
if (!initf)
|
||||
initf = tegra20_pinctrl_init;
|
||||
#endif
|
||||
if (!initf) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not determine SoC-specific init func\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
|
||||
if (!pmx) {
|
||||
dev_err(&pdev->dev, "Can't alloc tegra_pmx\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
pmx->dev = &pdev->dev;
|
||||
|
||||
(*initf)(&pmx->soc);
|
||||
|
||||
tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
|
||||
tegra_pinctrl_desc.pins = pmx->soc->pins;
|
||||
tegra_pinctrl_desc.npins = pmx->soc->npins;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (!res)
|
||||
break;
|
||||
}
|
||||
pmx->nbanks = i;
|
||||
|
||||
pmx->regs = devm_kzalloc(&pdev->dev, pmx->nbanks * sizeof(*pmx->regs),
|
||||
GFP_KERNEL);
|
||||
if (!pmx->regs) {
|
||||
dev_err(&pdev->dev, "Can't alloc regs pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < pmx->nbanks; i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Missing MEM resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res),
|
||||
dev_name(&pdev->dev))) {
|
||||
dev_err(&pdev->dev,
|
||||
"Couldn't request MEM resource %d\n", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pmx->regs[i] = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!pmx->regs[i]) {
|
||||
dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);
|
||||
if (IS_ERR(pmx->pctl)) {
|
||||
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
|
||||
return PTR_ERR(pmx->pctl);
|
||||
}
|
||||
|
||||
pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
|
||||
|
||||
platform_set_drvdata(pdev, pmx);
|
||||
|
||||
dev_dbg(&pdev->dev, "Probed Tegra pinctrl driver\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_pmx *pmx = platform_get_drvdata(pdev);
|
||||
|
||||
pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
|
||||
pinctrl_unregister(pmx->pctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tegra_pinctrl_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra_pinctrl_of_match,
|
||||
},
|
||||
.probe = tegra_pinctrl_probe,
|
||||
.remove = __devexit_p(tegra_pinctrl_remove),
|
||||
};
|
||||
|
||||
static int __init tegra_pinctrl_init(void)
|
||||
{
|
||||
return platform_driver_register(&tegra_pinctrl_driver);
|
||||
}
|
||||
arch_initcall(tegra_pinctrl_init);
|
||||
|
||||
static void __exit tegra_pinctrl_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tegra_pinctrl_driver);
|
||||
}
|
||||
module_exit(tegra_pinctrl_exit);
|
||||
|
||||
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match);
|
163
drivers/pinctrl/pinctrl-tegra.h
Normal file
163
drivers/pinctrl/pinctrl-tegra.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Driver for the NVIDIA Tegra pinmux
|
||||
*
|
||||
* Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef __PINMUX_TEGRA_H__
|
||||
#define __PINMUX_TEGRA_H__
|
||||
|
||||
/**
|
||||
* struct tegra_function - Tegra pinctrl mux function
|
||||
* @name: The name of the function, exported to pinctrl core.
|
||||
* @groups: An array of pin groups that may select this function.
|
||||
* @ngroups: The number of entries in @groups.
|
||||
*/
|
||||
struct tegra_function {
|
||||
const char *name;
|
||||
const char * const *groups;
|
||||
unsigned ngroups;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_pingroup - Tegra pin group
|
||||
* @mux_reg: Mux register offset. -1 if unsupported.
|
||||
* @mux_bank: Mux register bank. 0 if unsupported.
|
||||
* @mux_bit: Mux register bit. 0 if unsupported.
|
||||
* @pupd_reg: Pull-up/down register offset. -1 if unsupported.
|
||||
* @pupd_bank: Pull-up/down register bank. 0 if unsupported.
|
||||
* @pupd_bit: Pull-up/down register bit. 0 if unsupported.
|
||||
* @tri_reg: Tri-state register offset. -1 if unsupported.
|
||||
* @tri_bank: Tri-state register bank. 0 if unsupported.
|
||||
* @tri_bit: Tri-state register bit. 0 if unsupported.
|
||||
* @einput_reg: Enable-input register offset. -1 if unsupported.
|
||||
* @einput_bank: Enable-input register bank. 0 if unsupported.
|
||||
* @einput_bit: Enable-input register bit. 0 if unsupported.
|
||||
* @odrain_reg: Open-drain register offset. -1 if unsupported.
|
||||
* @odrain_bank: Open-drain register bank. 0 if unsupported.
|
||||
* @odrain_bit: Open-drain register bit. 0 if unsupported.
|
||||
* @lock_reg: Lock register offset. -1 if unsupported.
|
||||
* @lock_bank: Lock register bank. 0 if unsupported.
|
||||
* @lock_bit: Lock register bit. 0 if unsupported.
|
||||
* @ioreset_reg: IO reset register offset. -1 if unsupported.
|
||||
* @ioreset_bank: IO reset register bank. 0 if unsupported.
|
||||
* @ioreset_bit: IO reset register bit. 0 if unsupported.
|
||||
* @drv_reg: Drive fields register offset. -1 if unsupported.
|
||||
* This register contains the hsm, schmitt, lpmd, drvdn,
|
||||
* drvup, slwr, and slwf parameters.
|
||||
* @drv_bank: Drive fields register bank. 0 if unsupported.
|
||||
* @hsm_bit: High Speed Mode register bit. 0 if unsupported.
|
||||
* @schmitt_bit: Scmitt register bit. 0 if unsupported.
|
||||
* @lpmd_bit: Low Power Mode register bit. 0 if unsupported.
|
||||
* @drvdn_bit: Drive Down register bit. 0 if unsupported.
|
||||
* @drvdn_width: Drive Down field width. 0 if unsupported.
|
||||
* @drvup_bit: Drive Up register bit. 0 if unsupported.
|
||||
* @drvup_width: Drive Up field width. 0 if unsupported.
|
||||
* @slwr_bit: Slew Rising register bit. 0 if unsupported.
|
||||
* @slwr_width: Slew Rising field width. 0 if unsupported.
|
||||
* @slwf_bit: Slew Falling register bit. 0 if unsupported.
|
||||
* @slwf_width: Slew Falling field width. 0 if unsupported.
|
||||
*
|
||||
* A representation of a group of pins (possibly just one pin) in the Tegra
|
||||
* pin controller. Each group allows some parameter or parameters to be
|
||||
* configured. The most common is mux function selection. Many others exist
|
||||
* such as pull-up/down, tri-state, etc. Tegra's pin controller is complex;
|
||||
* certain groups may only support configuring certain parameters, hence
|
||||
* each parameter is optional, represented by a -1 "reg" value.
|
||||
*/
|
||||
struct tegra_pingroup {
|
||||
const char *name;
|
||||
const unsigned *pins;
|
||||
unsigned npins;
|
||||
unsigned funcs[4];
|
||||
unsigned func_safe;
|
||||
s16 mux_reg;
|
||||
s16 pupd_reg;
|
||||
s16 tri_reg;
|
||||
s16 einput_reg;
|
||||
s16 odrain_reg;
|
||||
s16 lock_reg;
|
||||
s16 ioreset_reg;
|
||||
s16 drv_reg;
|
||||
u32 mux_bank:2;
|
||||
u32 pupd_bank:2;
|
||||
u32 tri_bank:2;
|
||||
u32 einput_bank:2;
|
||||
u32 odrain_bank:2;
|
||||
u32 ioreset_bank:2;
|
||||
u32 lock_bank:2;
|
||||
u32 drv_bank:2;
|
||||
u32 mux_bit:5;
|
||||
u32 pupd_bit:5;
|
||||
u32 tri_bit:5;
|
||||
u32 einput_bit:5;
|
||||
u32 odrain_bit:5;
|
||||
u32 lock_bit:5;
|
||||
u32 ioreset_bit:5;
|
||||
u32 hsm_bit:5;
|
||||
u32 schmitt_bit:5;
|
||||
u32 lpmd_bit:5;
|
||||
u32 drvdn_bit:5;
|
||||
u32 drvup_bit:5;
|
||||
u32 slwr_bit:5;
|
||||
u32 slwf_bit:5;
|
||||
u32 drvdn_width:6;
|
||||
u32 drvup_width:6;
|
||||
u32 slwr_width:6;
|
||||
u32 slwf_width:6;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_pinctrl_soc_data - Tegra pin controller driver configuration
|
||||
* @ngpios: The number of GPIO pins the pin controller HW affects.
|
||||
* @pins: An array describing all pins the pin controller affects.
|
||||
* All pins which are also GPIOs must be listed first within the
|
||||
* array, and be numbered identically to the GPIO controller's
|
||||
* numbering.
|
||||
* @npins: The numbmer of entries in @pins.
|
||||
* @functions: An array describing all mux functions the SoC supports.
|
||||
* @nfunctions: The numbmer of entries in @functions.
|
||||
* @groups: An array describing all pin groups the pin SoC supports.
|
||||
* @ngroups: The numbmer of entries in @groups.
|
||||
*/
|
||||
struct tegra_pinctrl_soc_data {
|
||||
unsigned ngpios;
|
||||
const struct pinctrl_pin_desc *pins;
|
||||
unsigned npins;
|
||||
const struct tegra_function *functions;
|
||||
unsigned nfunctions;
|
||||
const struct tegra_pingroup *groups;
|
||||
unsigned ngroups;
|
||||
};
|
||||
|
||||
/**
|
||||
* tegra_pinctrl_soc_initf() - Retrieve pin controller details for a SoC.
|
||||
* @soc_data: This pointer must be updated to point at a struct containing
|
||||
* details of the SoC.
|
||||
*/
|
||||
typedef void (*tegra_pinctrl_soc_initf)(
|
||||
const struct tegra_pinctrl_soc_data **soc_data);
|
||||
|
||||
/**
|
||||
* tegra20_pinctrl_init() - Retrieve pin controller details for Tegra20
|
||||
* @soc_data: This pointer will be updated to point at a struct containing
|
||||
* details of Tegra20's pin controller.
|
||||
*/
|
||||
void tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
|
||||
/**
|
||||
* tegra30_pinctrl_init() - Retrieve pin controller details for Tegra20
|
||||
* @soc_data: This pointer will be updated to point at a struct containing
|
||||
* details of Tegra30's pin controller.
|
||||
*/
|
||||
void tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
|
||||
|
||||
#endif
|
2860
drivers/pinctrl/pinctrl-tegra20.c
Normal file
2860
drivers/pinctrl/pinctrl-tegra20.c
Normal file
File diff suppressed because it is too large
Load Diff
3726
drivers/pinctrl/pinctrl-tegra30.c
Normal file
3726
drivers/pinctrl/pinctrl-tegra30.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user