9
0
Fork 0

i.MX: Add pinctrl driver for VF610

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Andrey Smirnov 2016-11-09 08:13:55 -08:00 committed by Sascha Hauer
parent a4e1f15b6b
commit 49877e3125
3 changed files with 173 additions and 0 deletions

View File

@ -77,4 +77,9 @@ config PINCTRL_TEGRA_XUSB
source drivers/pinctrl/mvebu/Kconfig
config PINCTRL_VF610
bool
default y if ARCH_VF610
help
Pinmux controller found on Vybrid VF610 family of SoCs
endif

View File

@ -9,5 +9,6 @@ obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
obj-$(CONFIG_ARCH_MVEBU) += mvebu/

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2016 Zodiac Inflight Innovation
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that 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 <common.h>
#include <init.h>
#include <io.h>
#include <of.h>
#include <pinctrl.h>
#include <malloc.h>
#include <gpio.h>
enum {
PINCTRL_VF610_MUX_LINE_SIZE = 20,
PINCTRL_VF610_MUX_SHIFT = 20,
PINCTRL_VF610_IBE = 1 << 0,
PINCTRL_VF610_OBE = 1 << 1,
PINCTRL_VF610_xBE = 0b11,
};
struct pinctrl_vf610 {
void __iomem *base;
struct pinctrl_device pinctrl;
};
static int pinctrl_vf610_set_state(struct pinctrl_device *pdev,
struct device_node *np)
{
const __be32 *list;
int npins, size, i;
struct pinctrl_vf610 *iomux =
container_of(pdev, struct pinctrl_vf610, pinctrl);
list = of_get_property(np, "fsl,pins", &size);
if (!list)
return -EINVAL;
if (!size || size % PINCTRL_VF610_MUX_LINE_SIZE) {
dev_err(pdev->dev, "Invalid fsl,pins property in %s\n",
np->full_name);
return -EINVAL;
}
npins = size / PINCTRL_VF610_MUX_LINE_SIZE;
for (i = 0; i < npins; i++) {
u32 mux_reg = be32_to_cpu(*list++);
u32 input_reg = be32_to_cpu(*list++);
u32 mux_val = be32_to_cpu(*list++);
u32 input_val = be32_to_cpu(*list++);
u32 conf_val = be32_to_cpu(*list++);
writel(mux_val << PINCTRL_VF610_MUX_SHIFT | conf_val,
iomux->base + mux_reg);
if (input_reg)
writel(input_val, iomux->base + input_reg);
}
return 0;
}
static int pinctrl_vf610_set_direction(struct pinctrl_device *pdev,
unsigned int pin, bool input)
{
u32 pad_cr;
const u32 off = pin * sizeof(u32);
struct pinctrl_vf610 *iomux =
container_of(pdev, struct pinctrl_vf610, pinctrl);
pad_cr = readl(iomux->base + off);
if (input) {
pad_cr |= PINCTRL_VF610_IBE;
pad_cr &= ~PINCTRL_VF610_OBE;
} else {
pad_cr &= ~PINCTRL_VF610_IBE;
pad_cr |= PINCTRL_VF610_OBE;
}
writel(pad_cr, iomux->base + off);
return 0;
}
static int pinctrl_vf610_get_direction(struct pinctrl_device *pdev,
unsigned int pin)
{
const u32 off = pin * sizeof(u32);
struct pinctrl_vf610 *iomux =
container_of(pdev, struct pinctrl_vf610, pinctrl);
const u32 pad_cr = readl(iomux->base + off);
switch (pad_cr & PINCTRL_VF610_xBE) {
case PINCTRL_VF610_IBE:
return GPIOF_DIR_IN;
case PINCTRL_VF610_OBE:
return GPIOF_DIR_OUT;
default:
return -EINVAL;
}
}
static struct pinctrl_ops pinctrl_vf610_ops = {
.set_state = pinctrl_vf610_set_state,
.set_direction = pinctrl_vf610_set_direction,
.get_direction = pinctrl_vf610_get_direction,
};
static int pinctrl_vf610_probe(struct device_d *dev)
{
int ret;
struct resource *io;
struct pinctrl_vf610 *iomux;
iomux = xzalloc(sizeof(*iomux));
io = dev_request_mem_resource(dev, 0);
if (IS_ERR(io))
return PTR_ERR(io);
iomux->base = IOMEM(io->start);
iomux->pinctrl.dev = dev;
iomux->pinctrl.ops = &pinctrl_vf610_ops;
iomux->pinctrl.base = 0;
iomux->pinctrl.npins = ARCH_NR_GPIOS;
ret = pinctrl_register(&iomux->pinctrl);
if (ret)
free(iomux);
return ret;
}
static __maybe_unused struct of_device_id pinctrl_vf610_dt_ids[] = {
{ .compatible = "fsl,vf610-iomuxc", },
{ /* sentinel */ }
};
static struct driver_d pinctrl_vf610_driver = {
.name = "vf610-pinctrl",
.probe = pinctrl_vf610_probe,
.of_compatible = DRV_OF_COMPAT(pinctrl_vf610_dt_ids),
};
static int pinctrl_vf610_init(void)
{
return platform_driver_register(&pinctrl_vf610_driver);
}
postcore_initcall(pinctrl_vf610_init);