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 32static void __iomem *mpp_base; 33static void __iomem *high_mpp_base; 34 35static 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 50static 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(f5181l, f5182, f5281) \ 68 ((f5181l << 0) | (f5182 << 1) | (f5281 << 2)) 69 70enum orion_variant { 71 V_5181L = 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 77static 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_5181L), 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_5181L), 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 164static struct mvebu_mpp_ctrl orion_mpp_controls[] = { 165 MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl), 166}; 167 168static struct pinctrl_gpio_range mv88f5181l_gpio_ranges[] = { 169 MPP_GPIO_RANGE(0, 0, 0, 16), 170}; 171 172static struct pinctrl_gpio_range mv88f5182_gpio_ranges[] = { 173 MPP_GPIO_RANGE(0, 0, 0, 19), 174}; 175 176static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = { 177 MPP_GPIO_RANGE(0, 0, 0, 16), 178}; 179 180static struct mvebu_pinctrl_soc_info mv88f5181l_info = { 181 .variant = V_5181L, 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 = mv88f5181l_gpio_ranges, 187 .ngpioranges = ARRAY_SIZE(mv88f5181l_gpio_ranges), 188}; 189 190static 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 200static 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 */ 214static const struct of_device_id orion_pinctrl_of_match[] = { 215 { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181l_info }, 216 { .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info }, 217 { .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info }, 218 { } 219}; 220 221static int orion_pinctrl_probe(struct platform_device *pdev) 222{ 223 const struct of_device_id *match = 224 of_match_device(orion_pinctrl_of_match, &pdev->dev); 225 struct resource *res; 226 227 pdev->dev.platform_data = (void*)match->data; 228 229 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 230 mpp_base = devm_ioremap_resource(&pdev->dev, res); 231 if (IS_ERR(mpp_base)) 232 return PTR_ERR(mpp_base); 233 234 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 235 high_mpp_base = devm_ioremap_resource(&pdev->dev, res); 236 if (IS_ERR(high_mpp_base)) 237 return PTR_ERR(high_mpp_base); 238 239 return mvebu_pinctrl_probe(pdev); 240} 241 242static int orion_pinctrl_remove(struct platform_device *pdev) 243{ 244 return mvebu_pinctrl_remove(pdev); 245} 246 247static struct platform_driver orion_pinctrl_driver = { 248 .driver = { 249 .name = "orion-pinctrl", 250 .of_match_table = of_match_ptr(orion_pinctrl_of_match), 251 }, 252 .probe = orion_pinctrl_probe, 253 .remove = orion_pinctrl_remove, 254}; 255 256module_platform_driver(orion_pinctrl_driver); 257 258MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); 259MODULE_DESCRIPTION("Marvell Orion pinctrl driver"); 260MODULE_LICENSE("GPL v2"); 261