123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2019 DENX Software Engineering
- * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
- */
- #include <common.h>
- #include <log.h>
- #include <dm/device_compat.h>
- #include <dm/devres.h>
- #include <linux/io.h>
- #include <linux/err.h>
- #include <dm.h>
- #include <dm/pinctrl.h>
- #include <dm/read.h>
- #include "pinctrl-mxs.h"
- DECLARE_GLOBAL_DATA_PTR;
- struct mxs_pinctrl_priv {
- void __iomem *base;
- const struct mxs_regs *regs;
- };
- static unsigned long mxs_dt_node_to_map(struct udevice *conf)
- {
- unsigned long config = 0;
- int ret;
- u32 val;
- ret = dev_read_u32(conf, "fsl,drive-strength", &val);
- if (!ret)
- config = val | MA_PRESENT;
- ret = dev_read_u32(conf, "fsl,voltage", &val);
- if (!ret)
- config |= val << VOL_SHIFT | VOL_PRESENT;
- ret = dev_read_u32(conf, "fsl,pull-up", &val);
- if (!ret)
- config |= val << PULL_SHIFT | PULL_PRESENT;
- return config;
- }
- static int mxs_pinctrl_set_mux(struct udevice *dev, u32 val, int bank, int pin)
- {
- struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
- int muxsel = MUXID_TO_MUXSEL(val), shift;
- void __iomem *reg;
- reg = iomux->base + iomux->regs->muxsel;
- reg += bank * 0x20 + pin / 16 * 0x10;
- shift = pin % 16 * 2;
- mxs_pinctrl_rmwl(muxsel, 0x3, shift, reg);
- debug(" mux %d,", muxsel);
- return 0;
- }
- static int mxs_pinctrl_set_state(struct udevice *dev, struct udevice *conf)
- {
- struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
- u32 *pin_data, val, ma, vol, pull;
- int npins, size, i, ret;
- unsigned long config;
- debug("\n%s: set state: %s\n", __func__, conf->name);
- size = dev_read_size(conf, "fsl,pinmux-ids");
- if (size < 0)
- return size;
- if (!size || size % sizeof(int)) {
- dev_err(dev, "Invalid fsl,pinmux-ids property in %s\n",
- conf->name);
- return -EINVAL;
- }
- npins = size / sizeof(int);
- pin_data = devm_kzalloc(dev, size, 0);
- if (!pin_data)
- return -ENOMEM;
- ret = dev_read_u32_array(conf, "fsl,pinmux-ids", pin_data, npins);
- if (ret) {
- dev_err(dev, "Error reading pin data.\n");
- devm_kfree(dev, pin_data);
- return -EINVAL;
- }
- config = mxs_dt_node_to_map(conf);
- ma = CONFIG_TO_MA(config);
- vol = CONFIG_TO_VOL(config);
- pull = CONFIG_TO_PULL(config);
- for (i = 0; i < npins; i++) {
- int pinid, bank, pin, shift;
- void __iomem *reg;
- val = pin_data[i];
- pinid = MUXID_TO_PINID(val);
- bank = PINID_TO_BANK(pinid);
- pin = PINID_TO_PIN(pinid);
- debug("(val: 0x%x) pin %d,", val, pinid);
- /* Setup pinmux */
- mxs_pinctrl_set_mux(dev, val, bank, pin);
- debug(" ma: %d, vol: %d, pull: %d\n", ma, vol, pull);
- /* drive */
- reg = iomux->base + iomux->regs->drive;
- reg += bank * 0x40 + pin / 8 * 0x10;
- /* mA */
- if (config & MA_PRESENT) {
- shift = pin % 8 * 4;
- mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
- }
- /* vol */
- if (config & VOL_PRESENT) {
- shift = pin % 8 * 4 + 2;
- if (vol)
- writel(1 << shift, reg + SET);
- else
- writel(1 << shift, reg + CLR);
- }
- /* pull */
- if (config & PULL_PRESENT) {
- reg = iomux->base + iomux->regs->pull;
- reg += bank * 0x10;
- shift = pin;
- if (pull)
- writel(1 << shift, reg + SET);
- else
- writel(1 << shift, reg + CLR);
- }
- }
- devm_kfree(dev, pin_data);
- return 0;
- }
- static struct pinctrl_ops mxs_pinctrl_ops = {
- .set_state = mxs_pinctrl_set_state,
- };
- static int mxs_pinctrl_probe(struct udevice *dev)
- {
- struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
- iomux->base = dev_read_addr_ptr(dev);
- iomux->regs = (struct mxs_regs *)dev_get_driver_data(dev);
- return 0;
- }
- static const struct mxs_regs imx23_regs = {
- .muxsel = 0x100,
- .drive = 0x200,
- .pull = 0x400,
- };
- static const struct mxs_regs imx28_regs = {
- .muxsel = 0x100,
- .drive = 0x300,
- .pull = 0x600,
- };
- static const struct udevice_id mxs_pinctrl_match[] = {
- { .compatible = "fsl,imx23-pinctrl", .data = (ulong)&imx23_regs },
- { .compatible = "fsl,imx28-pinctrl", .data = (ulong)&imx28_regs },
- { /* sentinel */ }
- };
- U_BOOT_DRIVER(fsl_imx23_pinctrl) = {
- .name = "fsl_imx23_pinctrl",
- .id = UCLASS_PINCTRL,
- .of_match = of_match_ptr(mxs_pinctrl_match),
- .probe = mxs_pinctrl_probe,
- #if !CONFIG_IS_ENABLED(OF_PLATDATA)
- .bind = dm_scan_fdt_dev,
- #endif
- .priv_auto = sizeof(struct mxs_pinctrl_priv),
- .ops = &mxs_pinctrl_ops,
- };
- DM_DRIVER_ALIAS(fsl_imx23_pinctrl, fsl_imx28_pinctrl)
|