Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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
 51static 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
 62int 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}
 80EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT);
 81
 82static 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
 87static const struct resource vsc7512_miim1_resources[] = {
 88	DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"),
 89};
 90
 91static const struct resource vsc7512_pinctrl_resources[] = {
 92	DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"),
 93};
 94
 95static 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
 99static 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
127static 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
136static 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
145int 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}
156EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT);
157
158MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver");
159MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>");
160MODULE_LICENSE("GPL");
161MODULE_IMPORT_NS(MFD_OCELOT_SPI);