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