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