235 lines · c
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 an6 * on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is7 * intended to be the bus-agnostic glue between, for example, the SPI bus and8 * 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 0x000832 33#define BIT_SOFT_CHIP_RST BIT(0)34 35#define VSC7512_MIIM0_RES_START 0x7107009c36#define VSC7512_MIIM1_RES_START 0x710700c037#define VSC7512_MIIM_RES_SIZE 0x0000002438 39#define VSC7512_PHY_RES_START 0x710700f040#define VSC7512_PHY_RES_SIZE 0x0000000441 42#define VSC7512_GPIO_RES_START 0x7107003443#define VSC7512_GPIO_RES_SIZE 0x0000006c44 45#define VSC7512_SIO_CTRL_RES_START 0x710700f846#define VSC7512_SIO_CTRL_RES_SIZE 0x0000010047 48#define VSC7512_HSIO_RES_START 0x710d000049#define VSC7512_HSIO_RES_SIZE 0x0000012850 51#define VSC7512_ANA_RES_START 0x7188000052#define VSC7512_ANA_RES_SIZE 0x0001000053 54#define VSC7512_QS_RES_START 0x7108000055#define VSC7512_QS_RES_SIZE 0x0000010056 57#define VSC7512_QSYS_RES_START 0x7180000058#define VSC7512_QSYS_RES_SIZE 0x0020000059 60#define VSC7512_REW_RES_START 0x7103000061#define VSC7512_REW_RES_SIZE 0x0001000062 63#define VSC7512_SYS_RES_START 0x7101000064#define VSC7512_SYS_RES_SIZE 0x0001000065 66#define VSC7512_S0_RES_START 0x7104000067#define VSC7512_S1_RES_START 0x7105000068#define VSC7512_S2_RES_START 0x7106000069#define VCAP_RES_SIZE 0x0000040070 71#define VSC7512_PORT_0_RES_START 0x711e000072#define VSC7512_PORT_1_RES_START 0x711f000073#define VSC7512_PORT_2_RES_START 0x7120000074#define VSC7512_PORT_3_RES_START 0x7121000075#define VSC7512_PORT_4_RES_START 0x7122000076#define VSC7512_PORT_5_RES_START 0x7123000077#define VSC7512_PORT_6_RES_START 0x7124000078#define VSC7512_PORT_7_RES_START 0x7125000079#define VSC7512_PORT_8_RES_START 0x7126000080#define VSC7512_PORT_9_RES_START 0x7127000081#define VSC7512_PORT_10_RES_START 0x7128000082#define VSC7512_PORT_RES_SIZE 0x0001000083 84#define VSC7512_GCB_RST_SLEEP_US 10085#define VSC7512_GCB_RST_TIMEOUT_US 10000086 87static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata)88{89 int val, err;90 91 err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val);92 if (err)93 return err;94 95 return val;96}97 98int ocelot_chip_reset(struct device *dev)99{100 struct ocelot_ddata *ddata = dev_get_drvdata(dev);101 int ret, val;102 103 /*104 * Reset the entire chip here to put it into a completely known state.105 * Other drivers may want to reset their own subsystems. The register106 * self-clears, so one write is all that is needed and wait for it to107 * clear.108 */109 ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST);110 if (ret)111 return ret;112 113 return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val,114 VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US);115}116EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT);117 118static const struct resource vsc7512_miim0_resources[] = {119 DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"),120 DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"),121};122 123static const struct resource vsc7512_miim1_resources[] = {124 DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"),125};126 127static const struct resource vsc7512_pinctrl_resources[] = {128 DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"),129};130 131static const struct resource vsc7512_sgpio_resources[] = {132 DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"),133};134 135static const struct resource vsc7512_serdes_resources[] = {136 DEFINE_RES_REG_NAMED(VSC7512_HSIO_RES_START, VSC7512_HSIO_RES_SIZE, "hsio"),137};138 139static const struct resource vsc7512_switch_resources[] = {140 DEFINE_RES_REG_NAMED(VSC7512_ANA_RES_START, VSC7512_ANA_RES_SIZE, "ana"),141 DEFINE_RES_REG_NAMED(VSC7512_HSIO_RES_START, VSC7512_HSIO_RES_SIZE, "hsio"),142 DEFINE_RES_REG_NAMED(VSC7512_QS_RES_START, VSC7512_QS_RES_SIZE, "qs"),143 DEFINE_RES_REG_NAMED(VSC7512_QSYS_RES_START, VSC7512_QSYS_RES_SIZE, "qsys"),144 DEFINE_RES_REG_NAMED(VSC7512_REW_RES_START, VSC7512_REW_RES_SIZE, "rew"),145 DEFINE_RES_REG_NAMED(VSC7512_SYS_RES_START, VSC7512_SYS_RES_SIZE, "sys"),146 DEFINE_RES_REG_NAMED(VSC7512_S0_RES_START, VCAP_RES_SIZE, "s0"),147 DEFINE_RES_REG_NAMED(VSC7512_S1_RES_START, VCAP_RES_SIZE, "s1"),148 DEFINE_RES_REG_NAMED(VSC7512_S2_RES_START, VCAP_RES_SIZE, "s2"),149 DEFINE_RES_REG_NAMED(VSC7512_PORT_0_RES_START, VSC7512_PORT_RES_SIZE, "port0"),150 DEFINE_RES_REG_NAMED(VSC7512_PORT_1_RES_START, VSC7512_PORT_RES_SIZE, "port1"),151 DEFINE_RES_REG_NAMED(VSC7512_PORT_2_RES_START, VSC7512_PORT_RES_SIZE, "port2"),152 DEFINE_RES_REG_NAMED(VSC7512_PORT_3_RES_START, VSC7512_PORT_RES_SIZE, "port3"),153 DEFINE_RES_REG_NAMED(VSC7512_PORT_4_RES_START, VSC7512_PORT_RES_SIZE, "port4"),154 DEFINE_RES_REG_NAMED(VSC7512_PORT_5_RES_START, VSC7512_PORT_RES_SIZE, "port5"),155 DEFINE_RES_REG_NAMED(VSC7512_PORT_6_RES_START, VSC7512_PORT_RES_SIZE, "port6"),156 DEFINE_RES_REG_NAMED(VSC7512_PORT_7_RES_START, VSC7512_PORT_RES_SIZE, "port7"),157 DEFINE_RES_REG_NAMED(VSC7512_PORT_8_RES_START, VSC7512_PORT_RES_SIZE, "port8"),158 DEFINE_RES_REG_NAMED(VSC7512_PORT_9_RES_START, VSC7512_PORT_RES_SIZE, "port9"),159 DEFINE_RES_REG_NAMED(VSC7512_PORT_10_RES_START, VSC7512_PORT_RES_SIZE, "port10")160};161 162static const struct mfd_cell vsc7512_devs[] = {163 {164 .name = "ocelot-pinctrl",165 .of_compatible = "mscc,ocelot-pinctrl",166 .num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources),167 .resources = vsc7512_pinctrl_resources,168 }, {169 .name = "ocelot-sgpio",170 .of_compatible = "mscc,ocelot-sgpio",171 .num_resources = ARRAY_SIZE(vsc7512_sgpio_resources),172 .resources = vsc7512_sgpio_resources,173 }, {174 .name = "ocelot-miim0",175 .of_compatible = "mscc,ocelot-miim",176 .of_reg = VSC7512_MIIM0_RES_START,177 .use_of_reg = true,178 .num_resources = ARRAY_SIZE(vsc7512_miim0_resources),179 .resources = vsc7512_miim0_resources,180 }, {181 .name = "ocelot-miim1",182 .of_compatible = "mscc,ocelot-miim",183 .of_reg = VSC7512_MIIM1_RES_START,184 .use_of_reg = true,185 .num_resources = ARRAY_SIZE(vsc7512_miim1_resources),186 .resources = vsc7512_miim1_resources,187 }, {188 .name = "ocelot-serdes",189 .of_compatible = "mscc,vsc7514-serdes",190 .num_resources = ARRAY_SIZE(vsc7512_serdes_resources),191 .resources = vsc7512_serdes_resources,192 }, {193 .name = "ocelot-ext-switch",194 .of_compatible = "mscc,vsc7512-switch",195 .num_resources = ARRAY_SIZE(vsc7512_switch_resources),196 .resources = vsc7512_switch_resources,197 },198};199 200static void ocelot_core_try_add_regmap(struct device *dev,201 const struct resource *res)202{203 if (dev_get_regmap(dev, res->name))204 return;205 206 ocelot_spi_init_regmap(dev, res);207}208 209static void ocelot_core_try_add_regmaps(struct device *dev,210 const struct mfd_cell *cell)211{212 int i;213 214 for (i = 0; i < cell->num_resources; i++)215 ocelot_core_try_add_regmap(dev, &cell->resources[i]);216}217 218int ocelot_core_init(struct device *dev)219{220 int i, ndevs;221 222 ndevs = ARRAY_SIZE(vsc7512_devs);223 224 for (i = 0; i < ndevs; i++)225 ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]);226 227 return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL);228}229EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT);230 231MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver");232MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>");233MODULE_LICENSE("GPL");234MODULE_IMPORT_NS(MFD_OCELOT_SPI);235