9
0
Fork 0
barebox/drivers/pinctrl/pinctrl-single.c

167 lines
3.5 KiB
C

/*
* pinctrl-single - Generic device tree based pinctrl driver for one
* register per pin type pinmux controllers
*
* Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>
*
* 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 <pinctrl.h>
#include <malloc.h>
struct pinctrl_single {
void __iomem *base;
struct pinctrl_device pinctrl;
unsigned (*read)(void __iomem *reg);
void (*write)(unsigned val, void __iomem *reg);
unsigned width;
};
static unsigned __maybe_unused pcs_readb(void __iomem *reg)
{
return readb(reg);
}
static unsigned __maybe_unused pcs_readw(void __iomem *reg)
{
return readw(reg);
}
static unsigned __maybe_unused pcs_readl(void __iomem *reg)
{
return readl(reg);
}
static void __maybe_unused pcs_writeb(unsigned val, void __iomem *reg)
{
writeb(val, reg);
}
static void __maybe_unused pcs_writew(unsigned val, void __iomem *reg)
{
writew(val, reg);
}
static void __maybe_unused pcs_writel(unsigned val, void __iomem *reg)
{
writel(val, reg);
}
static int pcs_set_state(struct pinctrl_device *pdev, struct device_node *np)
{
struct pinctrl_single *pcs = container_of(pdev, struct pinctrl_single, pinctrl);
unsigned size = 0, index = 0;
const __be32 *mux;
dev_dbg(pcs->pinctrl.dev, "set state: %s\n", np->full_name);
mux = of_get_property(np, "pinctrl-single,pins", &size);
size /= sizeof(*mux); /* Number of elements in array */
if (!mux || !size || (size & 1)) {
dev_err(pcs->pinctrl.dev, "bad data for mux %s\n",
np->full_name);
return -EINVAL;
}
while (index < size) {
unsigned offset, val;
offset = be32_to_cpup(mux + index++);
val = be32_to_cpup(mux + index++);
pcs->write(val, pcs->base + offset);
}
return 0;
}
static struct pinctrl_ops pcs_ops = {
.set_state = pcs_set_state,
};
static int pcs_probe(struct device_d *dev)
{
struct pinctrl_single *pcs;
struct device_node *np = dev->device_node;
int ret = 0;
pcs = xzalloc(sizeof(*pcs));
pcs->base = dev_request_mem_region(dev, 0);
pcs->pinctrl.dev = dev;
pcs->pinctrl.ops = &pcs_ops;
ret = of_property_read_u32(np, "pinctrl-single,register-width",
&pcs->width);
if (ret) {
dev_dbg(dev, "no pinctrl-single,register-width property\n");
goto out;
}
switch (pcs->width) {
case 8:
pcs->read = pcs_readb;
pcs->write = pcs_writeb;
break;
case 16:
pcs->read = pcs_readw;
pcs->write = pcs_writew;
break;
case 32:
pcs->read = pcs_readl;
pcs->write = pcs_writel;
break;
default:
ret = -EINVAL;
dev_dbg(dev, "invalid register width: %d\n", pcs->width);
goto out;
}
ret = pinctrl_register(&pcs->pinctrl);
if (ret)
goto out;
return 0;
out:
free(pcs);
return ret;
}
static __maybe_unused struct of_device_id pcs_dt_ids[] = {
{
.compatible = "pinctrl-single",
}, {
/* sentinel */
}
};
static struct driver_d pcs_driver = {
.name = "pinctrl-single",
.probe = pcs_probe,
.of_compatible = DRV_OF_COMPAT(pcs_dt_ids),
};
static int pcs_init(void)
{
return platform_driver_register(&pcs_driver);
}
postcore_initcall(pcs_init);