From 26c725874bc92ecf92885f86386da82d04a85b2c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 19 Nov 2013 12:06:40 +0100 Subject: [PATCH] pinctrl: Add pinctrl-single driver Based on the kernel pinctrl-single driver. This one is just enough to make OMAP/AM33xx work. Signed-off-by: Sascha Hauer --- drivers/pinctrl/Kconfig | 3 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-single.c | 166 +++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-single.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 58397a0ac..825758692 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -23,6 +23,9 @@ config PINCTRL_IMX_IOMUX_V3 help This iomux controller is found on i.MX25,35,51,53,6. +config PINCTRL_SINGLE + bool "pinctrl single" + config PINCTRL_TEGRA20 select PINCTRL bool diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 169ed184c..b3b0fa9c5 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V1) += imx-iomux-v1.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V2) += imx-iomux-v2.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V3) += imx-iomux-v3.o +obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c new file mode 100644 index 000000000..5c60c70b1 --- /dev/null +++ b/drivers/pinctrl/pinctrl-single.c @@ -0,0 +1,166 @@ +/* + * pinctrl-single - Generic device tree based pinctrl driver for one + * register per pin type pinmux controllers + * + * Copyright (c) 2013 Sascha Hauer + * + * 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 +#include +#include +#include +#include + +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);