1 // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 /* 3 * Core driver for the Ocelot chip family. 4 * 5 * The VSC7511, 7512, 7513, and 7514 can be controlled internally via an 6 * on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is 7 * intended to be the bus-agnostic glue between, for example, the SPI bus and 8 * the child devices. 9 * 10 * Copyright 2021-2022 Innovative Advantage Inc. 11 * 12 * Author: Colin Foster <colin.foster@in-advantage.com> 13 */ 14 15 #include <linux/bits.h> 16 #include <linux/device.h> 17 #include <linux/export.h> 18 #include <linux/iopoll.h> 19 #include <linux/ioport.h> 20 #include <linux/kernel.h> 21 #include <linux/mfd/core.h> 22 #include <linux/mfd/ocelot.h> 23 #include <linux/module.h> 24 #include <linux/regmap.h> 25 #include <linux/types.h> 26 27 #include <soc/mscc/ocelot.h> 28 29 #include "ocelot.h" 30 31 #define REG_GCB_SOFT_RST 0x0008 32 33 #define BIT_SOFT_CHIP_RST BIT(0) 34 35 #define VSC7512_MIIM0_RES_START 0x7107009c 36 #define VSC7512_MIIM1_RES_START 0x710700c0 37 #define VSC7512_MIIM_RES_SIZE 0x00000024 38 39 #define VSC7512_PHY_RES_START 0x710700f0 40 #define VSC7512_PHY_RES_SIZE 0x00000004 41 42 #define VSC7512_GPIO_RES_START 0x71070034 43 #define VSC7512_GPIO_RES_SIZE 0x0000006c 44 45 #define VSC7512_SIO_CTRL_RES_START 0x710700f8 46 #define VSC7512_SIO_CTRL_RES_SIZE 0x00000100 47 48 #define VSC7512_ANA_RES_START 0x71880000 49 #define VSC7512_ANA_RES_SIZE 0x00010000 50 51 #define VSC7512_QS_RES_START 0x71080000 52 #define VSC7512_QS_RES_SIZE 0x00000100 53 54 #define VSC7512_QSYS_RES_START 0x71800000 55 #define VSC7512_QSYS_RES_SIZE 0x00200000 56 57 #define VSC7512_REW_RES_START 0x71030000 58 #define VSC7512_REW_RES_SIZE 0x00010000 59 60 #define VSC7512_SYS_RES_START 0x71010000 61 #define VSC7512_SYS_RES_SIZE 0x00010000 62 63 #define VSC7512_S0_RES_START 0x71040000 64 #define VSC7512_S1_RES_START 0x71050000 65 #define VSC7512_S2_RES_START 0x71060000 66 #define VCAP_RES_SIZE 0x00000400 67 68 #define VSC7512_PORT_0_RES_START 0x711e0000 69 #define VSC7512_PORT_1_RES_START 0x711f0000 70 #define VSC7512_PORT_2_RES_START 0x71200000 71 #define VSC7512_PORT_3_RES_START 0x71210000 72 #define VSC7512_PORT_4_RES_START 0x71220000 73 #define VSC7512_PORT_5_RES_START 0x71230000 74 #define VSC7512_PORT_6_RES_START 0x71240000 75 #define VSC7512_PORT_7_RES_START 0x71250000 76 #define VSC7512_PORT_8_RES_START 0x71260000 77 #define VSC7512_PORT_9_RES_START 0x71270000 78 #define VSC7512_PORT_10_RES_START 0x71280000 79 #define VSC7512_PORT_RES_SIZE 0x00010000 80 81 #define VSC7512_GCB_RST_SLEEP_US 100 82 #define VSC7512_GCB_RST_TIMEOUT_US 100000 83 84 static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata) 85 { 86 int val, err; 87 88 err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val); 89 if (err) 90 return err; 91 92 return val; 93 } 94 95 int ocelot_chip_reset(struct device *dev) 96 { 97 struct ocelot_ddata *ddata = dev_get_drvdata(dev); 98 int ret, val; 99 100 /* 101 * Reset the entire chip here to put it into a completely known state. 102 * Other drivers may want to reset their own subsystems. The register 103 * self-clears, so one write is all that is needed and wait for it to 104 * clear. 105 */ 106 ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST); 107 if (ret) 108 return ret; 109 110 return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val, 111 VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US); 112 } 113 EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT); 114 115 static const struct resource vsc7512_miim0_resources[] = { 116 DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"), 117 DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"), 118 }; 119 120 static const struct resource vsc7512_miim1_resources[] = { 121 DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"), 122 }; 123 124 static const struct resource vsc7512_pinctrl_resources[] = { 125 DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"), 126 }; 127 128 static const struct resource vsc7512_sgpio_resources[] = { 129 DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"), 130 }; 131 132 static const struct resource vsc7512_switch_resources[] = { 133 DEFINE_RES_REG_NAMED(VSC7512_ANA_RES_START, VSC7512_ANA_RES_SIZE, "ana"), 134 DEFINE_RES_REG_NAMED(VSC7512_QS_RES_START, VSC7512_QS_RES_SIZE, "qs"), 135 DEFINE_RES_REG_NAMED(VSC7512_QSYS_RES_START, VSC7512_QSYS_RES_SIZE, "qsys"), 136 DEFINE_RES_REG_NAMED(VSC7512_REW_RES_START, VSC7512_REW_RES_SIZE, "rew"), 137 DEFINE_RES_REG_NAMED(VSC7512_SYS_RES_START, VSC7512_SYS_RES_SIZE, "sys"), 138 DEFINE_RES_REG_NAMED(VSC7512_S0_RES_START, VCAP_RES_SIZE, "s0"), 139 DEFINE_RES_REG_NAMED(VSC7512_S1_RES_START, VCAP_RES_SIZE, "s1"), 140 DEFINE_RES_REG_NAMED(VSC7512_S2_RES_START, VCAP_RES_SIZE, "s2"), 141 DEFINE_RES_REG_NAMED(VSC7512_PORT_0_RES_START, VSC7512_PORT_RES_SIZE, "port0"), 142 DEFINE_RES_REG_NAMED(VSC7512_PORT_1_RES_START, VSC7512_PORT_RES_SIZE, "port1"), 143 DEFINE_RES_REG_NAMED(VSC7512_PORT_2_RES_START, VSC7512_PORT_RES_SIZE, "port2"), 144 DEFINE_RES_REG_NAMED(VSC7512_PORT_3_RES_START, VSC7512_PORT_RES_SIZE, "port3"), 145 DEFINE_RES_REG_NAMED(VSC7512_PORT_4_RES_START, VSC7512_PORT_RES_SIZE, "port4"), 146 DEFINE_RES_REG_NAMED(VSC7512_PORT_5_RES_START, VSC7512_PORT_RES_SIZE, "port5"), 147 DEFINE_RES_REG_NAMED(VSC7512_PORT_6_RES_START, VSC7512_PORT_RES_SIZE, "port6"), 148 DEFINE_RES_REG_NAMED(VSC7512_PORT_7_RES_START, VSC7512_PORT_RES_SIZE, "port7"), 149 DEFINE_RES_REG_NAMED(VSC7512_PORT_8_RES_START, VSC7512_PORT_RES_SIZE, "port8"), 150 DEFINE_RES_REG_NAMED(VSC7512_PORT_9_RES_START, VSC7512_PORT_RES_SIZE, "port9"), 151 DEFINE_RES_REG_NAMED(VSC7512_PORT_10_RES_START, VSC7512_PORT_RES_SIZE, "port10") 152 }; 153 154 static const struct mfd_cell vsc7512_devs[] = { 155 { 156 .name = "ocelot-pinctrl", 157 .of_compatible = "mscc,ocelot-pinctrl", 158 .num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources), 159 .resources = vsc7512_pinctrl_resources, 160 }, { 161 .name = "ocelot-sgpio", 162 .of_compatible = "mscc,ocelot-sgpio", 163 .num_resources = ARRAY_SIZE(vsc7512_sgpio_resources), 164 .resources = vsc7512_sgpio_resources, 165 }, { 166 .name = "ocelot-miim0", 167 .of_compatible = "mscc,ocelot-miim", 168 .of_reg = VSC7512_MIIM0_RES_START, 169 .use_of_reg = true, 170 .num_resources = ARRAY_SIZE(vsc7512_miim0_resources), 171 .resources = vsc7512_miim0_resources, 172 }, { 173 .name = "ocelot-miim1", 174 .of_compatible = "mscc,ocelot-miim", 175 .of_reg = VSC7512_MIIM1_RES_START, 176 .use_of_reg = true, 177 .num_resources = ARRAY_SIZE(vsc7512_miim1_resources), 178 .resources = vsc7512_miim1_resources, 179 }, { 180 .name = "ocelot-ext-switch", 181 .of_compatible = "mscc,vsc7512-switch", 182 .num_resources = ARRAY_SIZE(vsc7512_switch_resources), 183 .resources = vsc7512_switch_resources, 184 }, 185 }; 186 187 static void ocelot_core_try_add_regmap(struct device *dev, 188 const struct resource *res) 189 { 190 if (dev_get_regmap(dev, res->name)) 191 return; 192 193 ocelot_spi_init_regmap(dev, res); 194 } 195 196 static void ocelot_core_try_add_regmaps(struct device *dev, 197 const struct mfd_cell *cell) 198 { 199 int i; 200 201 for (i = 0; i < cell->num_resources; i++) 202 ocelot_core_try_add_regmap(dev, &cell->resources[i]); 203 } 204 205 int ocelot_core_init(struct device *dev) 206 { 207 int i, ndevs; 208 209 ndevs = ARRAY_SIZE(vsc7512_devs); 210 211 for (i = 0; i < ndevs; i++) 212 ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]); 213 214 return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL); 215 } 216 EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT); 217 218 MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver"); 219 MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>"); 220 MODULE_LICENSE("GPL"); 221 MODULE_IMPORT_NS(MFD_OCELOT_SPI); 222