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 0x024 38 39 #define VSC7512_PHY_RES_START 0x710700f0 40 #define VSC7512_PHY_RES_SIZE 0x004 41 42 #define VSC7512_GPIO_RES_START 0x71070034 43 #define VSC7512_GPIO_RES_SIZE 0x06c 44 45 #define VSC7512_SIO_CTRL_RES_START 0x710700f8 46 #define VSC7512_SIO_CTRL_RES_SIZE 0x100 47 48 #define VSC7512_GCB_RST_SLEEP_US 100 49 #define VSC7512_GCB_RST_TIMEOUT_US 100000 50 51 static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata) 52 { 53 int val, err; 54 55 err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val); 56 if (err) 57 return err; 58 59 return val; 60 } 61 62 int ocelot_chip_reset(struct device *dev) 63 { 64 struct ocelot_ddata *ddata = dev_get_drvdata(dev); 65 int ret, val; 66 67 /* 68 * Reset the entire chip here to put it into a completely known state. 69 * Other drivers may want to reset their own subsystems. The register 70 * self-clears, so one write is all that is needed and wait for it to 71 * clear. 72 */ 73 ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST); 74 if (ret) 75 return ret; 76 77 return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val, 78 VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US); 79 } 80 EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT); 81 82 static const struct resource vsc7512_miim0_resources[] = { 83 DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"), 84 DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"), 85 }; 86 87 static const struct resource vsc7512_miim1_resources[] = { 88 DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"), 89 }; 90 91 static const struct resource vsc7512_pinctrl_resources[] = { 92 DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"), 93 }; 94 95 static const struct resource vsc7512_sgpio_resources[] = { 96 DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"), 97 }; 98 99 static const struct mfd_cell vsc7512_devs[] = { 100 { 101 .name = "ocelot-pinctrl", 102 .of_compatible = "mscc,ocelot-pinctrl", 103 .num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources), 104 .resources = vsc7512_pinctrl_resources, 105 }, { 106 .name = "ocelot-sgpio", 107 .of_compatible = "mscc,ocelot-sgpio", 108 .num_resources = ARRAY_SIZE(vsc7512_sgpio_resources), 109 .resources = vsc7512_sgpio_resources, 110 }, { 111 .name = "ocelot-miim0", 112 .of_compatible = "mscc,ocelot-miim", 113 .of_reg = VSC7512_MIIM0_RES_START, 114 .use_of_reg = true, 115 .num_resources = ARRAY_SIZE(vsc7512_miim0_resources), 116 .resources = vsc7512_miim0_resources, 117 }, { 118 .name = "ocelot-miim1", 119 .of_compatible = "mscc,ocelot-miim", 120 .of_reg = VSC7512_MIIM1_RES_START, 121 .use_of_reg = true, 122 .num_resources = ARRAY_SIZE(vsc7512_miim1_resources), 123 .resources = vsc7512_miim1_resources, 124 }, 125 }; 126 127 static void ocelot_core_try_add_regmap(struct device *dev, 128 const struct resource *res) 129 { 130 if (dev_get_regmap(dev, res->name)) 131 return; 132 133 ocelot_spi_init_regmap(dev, res); 134 } 135 136 static void ocelot_core_try_add_regmaps(struct device *dev, 137 const struct mfd_cell *cell) 138 { 139 int i; 140 141 for (i = 0; i < cell->num_resources; i++) 142 ocelot_core_try_add_regmap(dev, &cell->resources[i]); 143 } 144 145 int ocelot_core_init(struct device *dev) 146 { 147 int i, ndevs; 148 149 ndevs = ARRAY_SIZE(vsc7512_devs); 150 151 for (i = 0; i < ndevs; i++) 152 ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]); 153 154 return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL); 155 } 156 EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT); 157 158 MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver"); 159 MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>"); 160 MODULE_LICENSE("GPL"); 161 MODULE_IMPORT_NS(MFD_OCELOT_SPI); 162