1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Marvell Orion pinctrl driver based on mvebu pinctrl core 4 * 5 * Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 6 * 7 * The first 16 MPP pins on Orion are easy to handle: they are 8 * configured through 2 consecutive registers, located at the base 9 * address of the MPP device. 10 * 11 * However the last 4 MPP pins are handled by a register at offset 12 * 0x50 from the base address, so it is not consecutive with the first 13 * two registers. 14 */ 15 16 #include <linux/err.h> 17 #include <linux/init.h> 18 #include <linux/io.h> 19 #include <linux/platform_device.h> 20 #include <linux/clk.h> 21 #include <linux/of.h> 22 #include <linux/pinctrl/pinctrl.h> 23 #include <linux/property.h> 24 25 #include "pinctrl-mvebu.h" 26 27 static void __iomem *mpp_base; 28 static void __iomem *high_mpp_base; 29 30 static int orion_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, 31 unsigned pid, unsigned long *config) 32 { 33 unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; 34 35 if (pid < 16) { 36 unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; 37 *config = (readl(mpp_base + off) >> shift) & MVEBU_MPP_MASK; 38 } 39 else { 40 *config = (readl(high_mpp_base) >> shift) & MVEBU_MPP_MASK; 41 } 42 43 return 0; 44 } 45 46 static int orion_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, 47 unsigned pid, unsigned long config) 48 { 49 unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; 50 51 if (pid < 16) { 52 unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; 53 u32 reg = readl(mpp_base + off) & ~(MVEBU_MPP_MASK << shift); 54 writel(reg | (config << shift), mpp_base + off); 55 } 56 else { 57 u32 reg = readl(high_mpp_base) & ~(MVEBU_MPP_MASK << shift); 58 writel(reg | (config << shift), high_mpp_base); 59 } 60 61 return 0; 62 } 63 64 #define V(f5181, f5182, f5281) \ 65 ((f5181 << 0) | (f5182 << 1) | (f5281 << 2)) 66 67 enum orion_variant { 68 V_5181 = V(1, 0, 0), 69 V_5182 = V(0, 1, 0), 70 V_5281 = V(0, 0, 1), 71 V_ALL = V(1, 1, 1), 72 }; 73 74 static struct mvebu_mpp_mode orion_mpp_modes[] = { 75 MPP_MODE(0, 76 MPP_VAR_FUNCTION(0x0, "pcie", "rstout", V_ALL), 77 MPP_VAR_FUNCTION(0x2, "pci", "req2", V_ALL), 78 MPP_VAR_FUNCTION(0x3, "gpio", NULL, V_ALL)), 79 MPP_MODE(1, 80 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 81 MPP_VAR_FUNCTION(0x2, "pci", "gnt2", V_ALL)), 82 MPP_MODE(2, 83 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 84 MPP_VAR_FUNCTION(0x2, "pci", "req3", V_ALL), 85 MPP_VAR_FUNCTION(0x3, "pci-1", "pme", V_ALL)), 86 MPP_MODE(3, 87 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 88 MPP_VAR_FUNCTION(0x2, "pci", "gnt3", V_ALL)), 89 MPP_MODE(4, 90 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 91 MPP_VAR_FUNCTION(0x2, "pci", "req4", V_ALL), 92 MPP_VAR_FUNCTION(0x4, "bootnand", "re", V_5182 | V_5281), 93 MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V_5182)), 94 MPP_MODE(5, 95 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 96 MPP_VAR_FUNCTION(0x2, "pci", "gnt4", V_ALL), 97 MPP_VAR_FUNCTION(0x4, "bootnand", "we", V_5182 | V_5281), 98 MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V_5182)), 99 MPP_MODE(6, 100 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 101 MPP_VAR_FUNCTION(0x2, "pci", "req5", V_ALL), 102 MPP_VAR_FUNCTION(0x4, "nand", "re0", V_5182 | V_5281), 103 MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181), 104 MPP_VAR_FUNCTION(0x5, "sata0", "act", V_5182)), 105 MPP_MODE(7, 106 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 107 MPP_VAR_FUNCTION(0x2, "pci", "gnt5", V_ALL), 108 MPP_VAR_FUNCTION(0x4, "nand", "we0", V_5182 | V_5281), 109 MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181), 110 MPP_VAR_FUNCTION(0x5, "sata1", "act", V_5182)), 111 MPP_MODE(8, 112 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 113 MPP_VAR_FUNCTION(0x1, "ge", "col", V_ALL)), 114 MPP_MODE(9, 115 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 116 MPP_VAR_FUNCTION(0x1, "ge", "rxerr", V_ALL)), 117 MPP_MODE(10, 118 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 119 MPP_VAR_FUNCTION(0x1, "ge", "crs", V_ALL)), 120 MPP_MODE(11, 121 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 122 MPP_VAR_FUNCTION(0x1, "ge", "txerr", V_ALL)), 123 MPP_MODE(12, 124 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 125 MPP_VAR_FUNCTION(0x1, "ge", "txd4", V_ALL), 126 MPP_VAR_FUNCTION(0x4, "nand", "re1", V_5182 | V_5281), 127 MPP_VAR_FUNCTION(0x5, "sata0", "ledprsnt", V_5182)), 128 MPP_MODE(13, 129 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 130 MPP_VAR_FUNCTION(0x1, "ge", "txd5", V_ALL), 131 MPP_VAR_FUNCTION(0x4, "nand", "we1", V_5182 | V_5281), 132 MPP_VAR_FUNCTION(0x5, "sata1", "ledprsnt", V_5182)), 133 MPP_MODE(14, 134 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 135 MPP_VAR_FUNCTION(0x1, "ge", "txd6", V_ALL), 136 MPP_VAR_FUNCTION(0x4, "nand", "re2", V_5182 | V_5281), 137 MPP_VAR_FUNCTION(0x5, "sata0", "ledact", V_5182)), 138 MPP_MODE(15, 139 MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), 140 MPP_VAR_FUNCTION(0x1, "ge", "txd7", V_ALL), 141 MPP_VAR_FUNCTION(0x4, "nand", "we2", V_5182 | V_5281), 142 MPP_VAR_FUNCTION(0x5, "sata1", "ledact", V_5182)), 143 MPP_MODE(16, 144 MPP_VAR_FUNCTION(0x0, "uart1", "rxd", V_5182 | V_5281), 145 MPP_VAR_FUNCTION(0x1, "ge", "rxd4", V_ALL), 146 MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), 147 MPP_MODE(17, 148 MPP_VAR_FUNCTION(0x0, "uart1", "txd", V_5182 | V_5281), 149 MPP_VAR_FUNCTION(0x1, "ge", "rxd5", V_ALL), 150 MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), 151 MPP_MODE(18, 152 MPP_VAR_FUNCTION(0x0, "uart1", "cts", V_5182 | V_5281), 153 MPP_VAR_FUNCTION(0x1, "ge", "rxd6", V_ALL), 154 MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), 155 MPP_MODE(19, 156 MPP_VAR_FUNCTION(0x0, "uart1", "rts", V_5182 | V_5281), 157 MPP_VAR_FUNCTION(0x1, "ge", "rxd7", V_ALL), 158 MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), 159 }; 160 161 static const struct mvebu_mpp_ctrl orion_mpp_controls[] = { 162 MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl), 163 }; 164 165 static struct pinctrl_gpio_range mv88f5181_gpio_ranges[] = { 166 MPP_GPIO_RANGE(0, 0, 0, 16), 167 }; 168 169 static struct pinctrl_gpio_range mv88f5182_gpio_ranges[] = { 170 MPP_GPIO_RANGE(0, 0, 0, 19), 171 }; 172 173 static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = { 174 MPP_GPIO_RANGE(0, 0, 0, 16), 175 }; 176 177 static struct mvebu_pinctrl_soc_info mv88f5181_info = { 178 .variant = V_5181, 179 .controls = orion_mpp_controls, 180 .ncontrols = ARRAY_SIZE(orion_mpp_controls), 181 .modes = orion_mpp_modes, 182 .nmodes = ARRAY_SIZE(orion_mpp_modes), 183 .gpioranges = mv88f5181_gpio_ranges, 184 .ngpioranges = ARRAY_SIZE(mv88f5181_gpio_ranges), 185 }; 186 187 static struct mvebu_pinctrl_soc_info mv88f5182_info = { 188 .variant = V_5182, 189 .controls = orion_mpp_controls, 190 .ncontrols = ARRAY_SIZE(orion_mpp_controls), 191 .modes = orion_mpp_modes, 192 .nmodes = ARRAY_SIZE(orion_mpp_modes), 193 .gpioranges = mv88f5182_gpio_ranges, 194 .ngpioranges = ARRAY_SIZE(mv88f5182_gpio_ranges), 195 }; 196 197 static struct mvebu_pinctrl_soc_info mv88f5281_info = { 198 .variant = V_5281, 199 .controls = orion_mpp_controls, 200 .ncontrols = ARRAY_SIZE(orion_mpp_controls), 201 .modes = orion_mpp_modes, 202 .nmodes = ARRAY_SIZE(orion_mpp_modes), 203 .gpioranges = mv88f5281_gpio_ranges, 204 .ngpioranges = ARRAY_SIZE(mv88f5281_gpio_ranges), 205 }; 206 207 /* 208 * There are multiple variants of the Orion SoCs, but in terms of pin 209 * muxing, they are identical. 210 */ 211 static const struct of_device_id orion_pinctrl_of_match[] = { 212 { .compatible = "marvell,88f5181-pinctrl", .data = &mv88f5181_info }, 213 { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181_info }, 214 { .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info }, 215 { .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info }, 216 { } 217 }; 218 219 static int orion_pinctrl_probe(struct platform_device *pdev) 220 { 221 pdev->dev.platform_data = (void*)device_get_match_data(&pdev->dev); 222 223 mpp_base = devm_platform_ioremap_resource(pdev, 0); 224 if (IS_ERR(mpp_base)) 225 return PTR_ERR(mpp_base); 226 227 high_mpp_base = devm_platform_ioremap_resource(pdev, 1); 228 if (IS_ERR(high_mpp_base)) 229 return PTR_ERR(high_mpp_base); 230 231 return mvebu_pinctrl_probe(pdev); 232 } 233 234 static struct platform_driver orion_pinctrl_driver = { 235 .driver = { 236 .name = "orion-pinctrl", 237 .of_match_table = of_match_ptr(orion_pinctrl_of_match), 238 }, 239 .probe = orion_pinctrl_probe, 240 }; 241 builtin_platform_driver(orion_pinctrl_driver); 242