1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2019 DENX Software Engineering 4 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de 5 */ 6 7#include <common.h> 8#include <log.h> 9#include <asm/global_data.h> 10#include <dm/device_compat.h> 11#include <dm/devres.h> 12#include <linux/io.h> 13#include <linux/err.h> 14#include <dm.h> 15#include <dm/pinctrl.h> 16#include <dm/read.h> 17#include "pinctrl-mxs.h" 18 19DECLARE_GLOBAL_DATA_PTR; 20 21struct mxs_pinctrl_priv { 22 void __iomem *base; 23 const struct mxs_regs *regs; 24}; 25 26static unsigned long mxs_dt_node_to_map(struct udevice *conf) 27{ 28 unsigned long config = 0; 29 int ret; 30 u32 val; 31 32 ret = dev_read_u32(conf, "fsl,drive-strength", &val); 33 if (!ret) 34 config = val | MA_PRESENT; 35 36 ret = dev_read_u32(conf, "fsl,voltage", &val); 37 if (!ret) 38 config |= val << VOL_SHIFT | VOL_PRESENT; 39 40 ret = dev_read_u32(conf, "fsl,pull-up", &val); 41 if (!ret) 42 config |= val << PULL_SHIFT | PULL_PRESENT; 43 44 return config; 45} 46 47static int mxs_pinctrl_set_mux(struct udevice *dev, u32 val, int bank, int pin) 48{ 49 struct mxs_pinctrl_priv *iomux = dev_get_priv(dev); 50 int muxsel = MUXID_TO_MUXSEL(val), shift; 51 void __iomem *reg; 52 53 reg = iomux->base + iomux->regs->muxsel; 54 reg += bank * 0x20 + pin / 16 * 0x10; 55 shift = pin % 16 * 2; 56 57 mxs_pinctrl_rmwl(muxsel, 0x3, shift, reg); 58 debug(" mux %d,", muxsel); 59 60 return 0; 61} 62 63static int mxs_pinctrl_set_state(struct udevice *dev, struct udevice *conf) 64{ 65 struct mxs_pinctrl_priv *iomux = dev_get_priv(dev); 66 u32 *pin_data, val, ma, vol, pull; 67 int npins, size, i, ret; 68 unsigned long config; 69 70 debug("\n%s: set state: %s\n", __func__, conf->name); 71 72 size = dev_read_size(conf, "fsl,pinmux-ids"); 73 if (size < 0) 74 return size; 75 76 if (!size || size % sizeof(int)) { 77 dev_err(dev, "Invalid fsl,pinmux-ids property in %s\n", 78 conf->name); 79 return -EINVAL; 80 } 81 82 npins = size / sizeof(int); 83 84 pin_data = devm_kzalloc(dev, size, 0); 85 if (!pin_data) 86 return -ENOMEM; 87 88 ret = dev_read_u32_array(conf, "fsl,pinmux-ids", pin_data, npins); 89 if (ret) { 90 dev_err(dev, "Error reading pin data.\n"); 91 devm_kfree(dev, pin_data); 92 return -EINVAL; 93 } 94 95 config = mxs_dt_node_to_map(conf); 96 97 ma = CFG_TO_MA(config); 98 vol = CFG_TO_VOL(config); 99 pull = CFG_TO_PULL(config); 100 101 for (i = 0; i < npins; i++) { 102 int pinid, bank, pin, shift; 103 void __iomem *reg; 104 105 val = pin_data[i]; 106 107 pinid = MUXID_TO_PINID(val); 108 bank = PINID_TO_BANK(pinid); 109 pin = PINID_TO_PIN(pinid); 110 111 debug("(val: 0x%x) pin %d,", val, pinid); 112 /* Setup pinmux */ 113 mxs_pinctrl_set_mux(dev, val, bank, pin); 114 115 debug(" ma: %d, vol: %d, pull: %d\n", ma, vol, pull); 116 117 /* drive */ 118 reg = iomux->base + iomux->regs->drive; 119 reg += bank * 0x40 + pin / 8 * 0x10; 120 121 /* mA */ 122 if (config & MA_PRESENT) { 123 shift = pin % 8 * 4; 124 mxs_pinctrl_rmwl(ma, 0x3, shift, reg); 125 } 126 127 /* vol */ 128 if (config & VOL_PRESENT) { 129 shift = pin % 8 * 4 + 2; 130 if (vol) 131 writel(1 << shift, reg + SET); 132 else 133 writel(1 << shift, reg + CLR); 134 } 135 136 /* pull */ 137 if (config & PULL_PRESENT) { 138 reg = iomux->base + iomux->regs->pull; 139 reg += bank * 0x10; 140 shift = pin; 141 if (pull) 142 writel(1 << shift, reg + SET); 143 else 144 writel(1 << shift, reg + CLR); 145 } 146 } 147 148 devm_kfree(dev, pin_data); 149 return 0; 150} 151 152static struct pinctrl_ops mxs_pinctrl_ops = { 153 .set_state = mxs_pinctrl_set_state, 154}; 155 156static int mxs_pinctrl_probe(struct udevice *dev) 157{ 158 struct mxs_pinctrl_priv *iomux = dev_get_priv(dev); 159 160 iomux->base = dev_read_addr_ptr(dev); 161 iomux->regs = (struct mxs_regs *)dev_get_driver_data(dev); 162 163 return 0; 164} 165 166static const struct mxs_regs imx23_regs = { 167 .muxsel = 0x100, 168 .drive = 0x200, 169 .pull = 0x400, 170}; 171 172static const struct mxs_regs imx28_regs = { 173 .muxsel = 0x100, 174 .drive = 0x300, 175 .pull = 0x600, 176}; 177 178static const struct udevice_id mxs_pinctrl_match[] = { 179 { .compatible = "fsl,imx23-pinctrl", .data = (ulong)&imx23_regs }, 180 { .compatible = "fsl,imx28-pinctrl", .data = (ulong)&imx28_regs }, 181 { /* sentinel */ } 182}; 183 184U_BOOT_DRIVER(fsl_imx23_pinctrl) = { 185 .name = "fsl_imx23_pinctrl", 186 .id = UCLASS_PINCTRL, 187 .of_match = of_match_ptr(mxs_pinctrl_match), 188 .probe = mxs_pinctrl_probe, 189#if CONFIG_IS_ENABLED(OF_REAL) 190 .bind = dm_scan_fdt_dev, 191#endif 192 .priv_auto = sizeof(struct mxs_pinctrl_priv), 193 .ops = &mxs_pinctrl_ops, 194}; 195 196DM_DRIVER_ALIAS(fsl_imx23_pinctrl, fsl_imx28_pinctrl) 197