1*95c1762aSConor Dooley // SPDX-License-Identifier: GPL-2.0 2*95c1762aSConor Dooley 3*95c1762aSConor Dooley #include <linux/bitfield.h> 4*95c1762aSConor Dooley #include <linux/cleanup.h> 5*95c1762aSConor Dooley #include <linux/module.h> 6*95c1762aSConor Dooley #include <linux/mfd/syscon.h> 7*95c1762aSConor Dooley #include <linux/mod_devicetable.h> 8*95c1762aSConor Dooley #include <linux/of.h> 9*95c1762aSConor Dooley #include <linux/platform_device.h> 10*95c1762aSConor Dooley #include <linux/regmap.h> 11*95c1762aSConor Dooley #include <linux/seq_file.h> 12*95c1762aSConor Dooley 13*95c1762aSConor Dooley #include <linux/pinctrl/pinconf-generic.h> 14*95c1762aSConor Dooley #include <linux/pinctrl/pinconf.h> 15*95c1762aSConor Dooley #include <linux/pinctrl/pinctrl.h> 16*95c1762aSConor Dooley #include <linux/pinctrl/pinmux.h> 17*95c1762aSConor Dooley 18*95c1762aSConor Dooley #include "../core.h" 19*95c1762aSConor Dooley #include "../pinctrl-utils.h" 20*95c1762aSConor Dooley #include "../pinconf.h" 21*95c1762aSConor Dooley #include "../pinmux.h" 22*95c1762aSConor Dooley 23*95c1762aSConor Dooley #define MPFS_IOMUX0_REG 0x200 24*95c1762aSConor Dooley 25*95c1762aSConor Dooley struct mpfs_iomux0_pinctrl { 26*95c1762aSConor Dooley struct pinctrl_dev *pctrl; 27*95c1762aSConor Dooley struct device *dev; 28*95c1762aSConor Dooley struct regmap *regmap; 29*95c1762aSConor Dooley struct pinctrl_desc desc; 30*95c1762aSConor Dooley }; 31*95c1762aSConor Dooley 32*95c1762aSConor Dooley struct mpfs_iomux0_pin_group { 33*95c1762aSConor Dooley const char *name; 34*95c1762aSConor Dooley const unsigned int *pins; 35*95c1762aSConor Dooley u32 mask; 36*95c1762aSConor Dooley u32 setting; 37*95c1762aSConor Dooley }; 38*95c1762aSConor Dooley 39*95c1762aSConor Dooley struct mpfs_iomux0_function { 40*95c1762aSConor Dooley const char *name; 41*95c1762aSConor Dooley const char * const *groups; 42*95c1762aSConor Dooley }; 43*95c1762aSConor Dooley 44*95c1762aSConor Dooley static const struct pinctrl_pin_desc mpfs_iomux0_pins[] = { 45*95c1762aSConor Dooley PINCTRL_PIN(0, "spi0"), 46*95c1762aSConor Dooley PINCTRL_PIN(1, "spi1"), 47*95c1762aSConor Dooley PINCTRL_PIN(2, "i2c0"), 48*95c1762aSConor Dooley PINCTRL_PIN(3, "i2c1"), 49*95c1762aSConor Dooley PINCTRL_PIN(4, "can0"), 50*95c1762aSConor Dooley PINCTRL_PIN(5, "can1"), 51*95c1762aSConor Dooley PINCTRL_PIN(6, "qspi"), 52*95c1762aSConor Dooley PINCTRL_PIN(7, "uart0"), 53*95c1762aSConor Dooley PINCTRL_PIN(8, "uart1"), 54*95c1762aSConor Dooley PINCTRL_PIN(9, "uart2"), 55*95c1762aSConor Dooley PINCTRL_PIN(10, "uart3"), 56*95c1762aSConor Dooley PINCTRL_PIN(11, "uart4"), 57*95c1762aSConor Dooley PINCTRL_PIN(12, "mdio0"), 58*95c1762aSConor Dooley PINCTRL_PIN(13, "mdio1"), 59*95c1762aSConor Dooley }; 60*95c1762aSConor Dooley 61*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_spi0_pins[] = { 0 }; 62*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_spi1_pins[] = { 1 }; 63*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_i2c0_pins[] = { 2 }; 64*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_i2c1_pins[] = { 3 }; 65*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_can0_pins[] = { 4 }; 66*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_can1_pins[] = { 5 }; 67*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_qspi_pins[] = { 6 }; 68*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_uart0_pins[] = { 7 }; 69*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_uart1_pins[] = { 8 }; 70*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_uart2_pins[] = { 9 }; 71*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_uart3_pins[] = { 10 }; 72*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_uart4_pins[] = { 11 }; 73*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_mdio0_pins[] = { 12 }; 74*95c1762aSConor Dooley static const unsigned int mpfs_iomux0_mdio1_pins[] = { 13 }; 75*95c1762aSConor Dooley 76*95c1762aSConor Dooley #define MPFS_IOMUX0_GROUP(_name, _mask) { \ 77*95c1762aSConor Dooley .name = #_name "_mssio", \ 78*95c1762aSConor Dooley .pins = mpfs_iomux0_##_name##_pins, \ 79*95c1762aSConor Dooley .mask = _mask, \ 80*95c1762aSConor Dooley .setting = 0x0, \ 81*95c1762aSConor Dooley }, { \ 82*95c1762aSConor Dooley .name = #_name "_fabric", \ 83*95c1762aSConor Dooley .pins = mpfs_iomux0_##_name##_pins, \ 84*95c1762aSConor Dooley .mask = _mask, \ 85*95c1762aSConor Dooley .setting = _mask, \ 86*95c1762aSConor Dooley } 87*95c1762aSConor Dooley 88*95c1762aSConor Dooley static const struct mpfs_iomux0_pin_group mpfs_iomux0_pin_groups[] = { 89*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(spi0, BIT(0)), 90*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(spi1, BIT(1)), 91*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(i2c0, BIT(2)), 92*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(i2c1, BIT(3)), 93*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(can0, BIT(4)), 94*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(can1, BIT(5)), 95*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(qspi, BIT(6)), 96*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(uart0, BIT(7)), 97*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(uart1, BIT(8)), 98*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(uart2, BIT(9)), 99*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(uart3, BIT(10)), 100*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(uart4, BIT(11)), 101*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(mdio0, BIT(12)), 102*95c1762aSConor Dooley MPFS_IOMUX0_GROUP(mdio1, BIT(13)), 103*95c1762aSConor Dooley }; 104*95c1762aSConor Dooley 105*95c1762aSConor Dooley static const char * const mpfs_iomux0_spi0_groups[] = { "spi0_mssio", "spi0_fabric" }; 106*95c1762aSConor Dooley static const char * const mpfs_iomux0_spi1_groups[] = { "spi1_mssio", "spi1_fabric" }; 107*95c1762aSConor Dooley static const char * const mpfs_iomux0_i2c0_groups[] = { "i2c0_mssio", "i2c0_fabric" }; 108*95c1762aSConor Dooley static const char * const mpfs_iomux0_i2c1_groups[] = { "i2c1_mssio", "i2c1_fabric" }; 109*95c1762aSConor Dooley static const char * const mpfs_iomux0_can0_groups[] = { "can0_mssio", "can0_fabric" }; 110*95c1762aSConor Dooley static const char * const mpfs_iomux0_can1_groups[] = { "can1_mssio", "can1_fabric" }; 111*95c1762aSConor Dooley static const char * const mpfs_iomux0_qspi_groups[] = { "qspi_mssio", "qspi_fabric" }; 112*95c1762aSConor Dooley static const char * const mpfs_iomux0_uart0_groups[] = { "uart0_mssio", "uart0_fabric" }; 113*95c1762aSConor Dooley static const char * const mpfs_iomux0_uart1_groups[] = { "uart1_mssio", "uart1_fabric" }; 114*95c1762aSConor Dooley static const char * const mpfs_iomux0_uart2_groups[] = { "uart2_mssio", "uart2_fabric" }; 115*95c1762aSConor Dooley static const char * const mpfs_iomux0_uart3_groups[] = { "uart3_mssio", "uart3_fabric" }; 116*95c1762aSConor Dooley static const char * const mpfs_iomux0_uart4_groups[] = { "uart4_mssio", "uart4_fabric" }; 117*95c1762aSConor Dooley static const char * const mpfs_iomux0_mdio0_groups[] = { "mdio0_mssio", "mdio0_fabric" }; 118*95c1762aSConor Dooley static const char * const mpfs_iomux0_mdio1_groups[] = { "mdio1_mssio", "mdio1_fabric" }; 119*95c1762aSConor Dooley 120*95c1762aSConor Dooley #define MPFS_IOMUX0_FUNCTION(_name) { \ 121*95c1762aSConor Dooley .name = #_name, \ 122*95c1762aSConor Dooley .groups = mpfs_iomux0_##_name##_groups, \ 123*95c1762aSConor Dooley } 124*95c1762aSConor Dooley 125*95c1762aSConor Dooley static const struct mpfs_iomux0_function mpfs_iomux0_functions[] = { 126*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(spi0), 127*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(spi1), 128*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(i2c0), 129*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(i2c1), 130*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(can0), 131*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(can1), 132*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(qspi), 133*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(uart0), 134*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(uart1), 135*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(uart2), 136*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(uart3), 137*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(uart4), 138*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(mdio0), 139*95c1762aSConor Dooley MPFS_IOMUX0_FUNCTION(mdio1), 140*95c1762aSConor Dooley }; 141*95c1762aSConor Dooley 142*95c1762aSConor Dooley static void mpfs_iomux0_pin_dbg_show(struct pinctrl_dev *pctrl_dev, struct seq_file *seq, 143*95c1762aSConor Dooley unsigned int pin) 144*95c1762aSConor Dooley { 145*95c1762aSConor Dooley struct mpfs_iomux0_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); 146*95c1762aSConor Dooley u32 val; 147*95c1762aSConor Dooley 148*95c1762aSConor Dooley seq_printf(seq, "reg: %x, pin: %u ", MPFS_IOMUX0_REG, pin); 149*95c1762aSConor Dooley 150*95c1762aSConor Dooley regmap_read(pctrl->regmap, MPFS_IOMUX0_REG, &val); 151*95c1762aSConor Dooley val = (val & BIT(pin)) >> pin; 152*95c1762aSConor Dooley 153*95c1762aSConor Dooley seq_printf(seq, "val: %x\n", val); 154*95c1762aSConor Dooley } 155*95c1762aSConor Dooley 156*95c1762aSConor Dooley static int mpfs_iomux0_groups_count(struct pinctrl_dev *pctldev) 157*95c1762aSConor Dooley { 158*95c1762aSConor Dooley return ARRAY_SIZE(mpfs_iomux0_pin_groups); 159*95c1762aSConor Dooley } 160*95c1762aSConor Dooley 161*95c1762aSConor Dooley static const char *mpfs_iomux0_group_name(struct pinctrl_dev *pctldev, unsigned int selector) 162*95c1762aSConor Dooley { 163*95c1762aSConor Dooley return mpfs_iomux0_pin_groups[selector].name; 164*95c1762aSConor Dooley } 165*95c1762aSConor Dooley 166*95c1762aSConor Dooley static int mpfs_iomux0_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, 167*95c1762aSConor Dooley const unsigned int **pins, unsigned int *num_pins) 168*95c1762aSConor Dooley { 169*95c1762aSConor Dooley *pins = mpfs_iomux0_pin_groups[selector].pins; 170*95c1762aSConor Dooley *num_pins = 1; 171*95c1762aSConor Dooley 172*95c1762aSConor Dooley return 0; 173*95c1762aSConor Dooley } 174*95c1762aSConor Dooley 175*95c1762aSConor Dooley static const struct pinctrl_ops mpfs_iomux0_pinctrl_ops = { 176*95c1762aSConor Dooley .get_groups_count = mpfs_iomux0_groups_count, 177*95c1762aSConor Dooley .get_group_name = mpfs_iomux0_group_name, 178*95c1762aSConor Dooley .get_group_pins = mpfs_iomux0_group_pins, 179*95c1762aSConor Dooley .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 180*95c1762aSConor Dooley .dt_free_map = pinctrl_utils_free_map, 181*95c1762aSConor Dooley .pin_dbg_show = mpfs_iomux0_pin_dbg_show, 182*95c1762aSConor Dooley }; 183*95c1762aSConor Dooley 184*95c1762aSConor Dooley static int mpfs_iomux0_pinmux_set_mux(struct pinctrl_dev *pctrl_dev, unsigned int fsel, 185*95c1762aSConor Dooley unsigned int gsel) 186*95c1762aSConor Dooley { 187*95c1762aSConor Dooley struct mpfs_iomux0_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev); 188*95c1762aSConor Dooley struct device *dev = pctrl->dev; 189*95c1762aSConor Dooley const struct mpfs_iomux0_pin_group *group; 190*95c1762aSConor Dooley const struct mpfs_iomux0_function *function; 191*95c1762aSConor Dooley 192*95c1762aSConor Dooley group = &mpfs_iomux0_pin_groups[gsel]; 193*95c1762aSConor Dooley function = &mpfs_iomux0_functions[fsel]; 194*95c1762aSConor Dooley 195*95c1762aSConor Dooley dev_dbg(dev, "Setting func %s mask %x setting %x\n", 196*95c1762aSConor Dooley function->name, group->mask, group->setting); 197*95c1762aSConor Dooley regmap_assign_bits(pctrl->regmap, MPFS_IOMUX0_REG, group->mask, group->setting); 198*95c1762aSConor Dooley 199*95c1762aSConor Dooley return 0; 200*95c1762aSConor Dooley } 201*95c1762aSConor Dooley 202*95c1762aSConor Dooley static int mpfs_iomux0_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) 203*95c1762aSConor Dooley { 204*95c1762aSConor Dooley return ARRAY_SIZE(mpfs_iomux0_functions); 205*95c1762aSConor Dooley } 206*95c1762aSConor Dooley 207*95c1762aSConor Dooley static const char *mpfs_iomux0_pinmux_get_func_name(struct pinctrl_dev *pctldev, 208*95c1762aSConor Dooley unsigned int selector) 209*95c1762aSConor Dooley { 210*95c1762aSConor Dooley return mpfs_iomux0_functions[selector].name; 211*95c1762aSConor Dooley } 212*95c1762aSConor Dooley 213*95c1762aSConor Dooley static int mpfs_iomux0_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, 214*95c1762aSConor Dooley const char * const **groups, 215*95c1762aSConor Dooley unsigned int * const num_groups) 216*95c1762aSConor Dooley { 217*95c1762aSConor Dooley *groups = mpfs_iomux0_functions[selector].groups; 218*95c1762aSConor Dooley *num_groups = 2; 219*95c1762aSConor Dooley 220*95c1762aSConor Dooley return 0; 221*95c1762aSConor Dooley } 222*95c1762aSConor Dooley 223*95c1762aSConor Dooley static const struct pinmux_ops mpfs_iomux0_pinmux_ops = { 224*95c1762aSConor Dooley .get_functions_count = mpfs_iomux0_pinmux_get_funcs_count, 225*95c1762aSConor Dooley .get_function_name = mpfs_iomux0_pinmux_get_func_name, 226*95c1762aSConor Dooley .get_function_groups = mpfs_iomux0_pinmux_get_groups, 227*95c1762aSConor Dooley .set_mux = mpfs_iomux0_pinmux_set_mux, 228*95c1762aSConor Dooley }; 229*95c1762aSConor Dooley 230*95c1762aSConor Dooley static int mpfs_iomux0_probe(struct platform_device *pdev) 231*95c1762aSConor Dooley { 232*95c1762aSConor Dooley struct device *dev = &pdev->dev; 233*95c1762aSConor Dooley struct mpfs_iomux0_pinctrl *pctrl; 234*95c1762aSConor Dooley 235*95c1762aSConor Dooley pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); 236*95c1762aSConor Dooley if (!pctrl) 237*95c1762aSConor Dooley return -ENOMEM; 238*95c1762aSConor Dooley 239*95c1762aSConor Dooley pctrl->regmap = device_node_to_regmap(pdev->dev.parent->of_node); 240*95c1762aSConor Dooley if (IS_ERR(pctrl->regmap)) 241*95c1762aSConor Dooley dev_err_probe(dev, PTR_ERR(pctrl->regmap), "Failed to find syscon regmap\n"); 242*95c1762aSConor Dooley 243*95c1762aSConor Dooley pctrl->desc.name = dev_name(dev); 244*95c1762aSConor Dooley pctrl->desc.pins = mpfs_iomux0_pins; 245*95c1762aSConor Dooley pctrl->desc.npins = ARRAY_SIZE(mpfs_iomux0_pins); 246*95c1762aSConor Dooley pctrl->desc.pctlops = &mpfs_iomux0_pinctrl_ops; 247*95c1762aSConor Dooley pctrl->desc.pmxops = &mpfs_iomux0_pinmux_ops; 248*95c1762aSConor Dooley pctrl->desc.owner = THIS_MODULE; 249*95c1762aSConor Dooley 250*95c1762aSConor Dooley pctrl->dev = dev; 251*95c1762aSConor Dooley 252*95c1762aSConor Dooley platform_set_drvdata(pdev, pctrl); 253*95c1762aSConor Dooley 254*95c1762aSConor Dooley pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl); 255*95c1762aSConor Dooley if (IS_ERR(pctrl->pctrl)) 256*95c1762aSConor Dooley return PTR_ERR(pctrl->pctrl); 257*95c1762aSConor Dooley 258*95c1762aSConor Dooley return 0; 259*95c1762aSConor Dooley } 260*95c1762aSConor Dooley 261*95c1762aSConor Dooley static const struct of_device_id mpfs_iomux0_of_match[] = { 262*95c1762aSConor Dooley { .compatible = "microchip,mpfs-pinctrl-iomux0" }, 263*95c1762aSConor Dooley { } 264*95c1762aSConor Dooley }; 265*95c1762aSConor Dooley MODULE_DEVICE_TABLE(of, mpfs_iomux0_of_match); 266*95c1762aSConor Dooley 267*95c1762aSConor Dooley static struct platform_driver mpfs_iomux0_driver = { 268*95c1762aSConor Dooley .driver = { 269*95c1762aSConor Dooley .name = "mpfs-pinctrl-iomux0", 270*95c1762aSConor Dooley .of_match_table = mpfs_iomux0_of_match, 271*95c1762aSConor Dooley }, 272*95c1762aSConor Dooley .probe = mpfs_iomux0_probe, 273*95c1762aSConor Dooley }; 274*95c1762aSConor Dooley module_platform_driver(mpfs_iomux0_driver); 275*95c1762aSConor Dooley 276*95c1762aSConor Dooley MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); 277*95c1762aSConor Dooley MODULE_DESCRIPTION("Polarfire SoC iomux0 pinctrl driver"); 278*95c1762aSConor Dooley MODULE_LICENSE("GPL"); 279