Skip to content

Commit

Permalink
mfd: ocelot: add support for external mfd control over SPI for the VS…
Browse files Browse the repository at this point in the history
…C7512

Create a single SPI MFD ocelot device that manages the SPI bus on the
external chip and can handle requests for regmaps. This should allow any
ocelot driver (pinctrl, miim, etc.) to be used externally, provided they
utilize regmaps.

Signed-off-by: Colin Foster <colin.foster@in-advantage.com>
  • Loading branch information
colin-foster-in-advantage authored and intel-lab-lkp committed Jan 29, 2022
1 parent 8157583 commit 17c4774
Show file tree
Hide file tree
Showing 9 changed files with 614 additions and 17 deletions.
19 changes: 19 additions & 0 deletions drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,25 @@ config MFD_MENF21BMC
This driver can also be built as a module. If so the module
will be called menf21bmc.

config MFD_OCELOT
tristate "Microsemi Ocelot External Control Support"
select MFD_CORE
help
Say yes here to add support for Ocelot chips (VSC7511, VSC7512,
VSC7513, VSC7514) controlled externally.

All four of these chips can be controlled internally (MMIO) or
externally via SPI, I2C, PCIe. This enables control of these chips
over one or more of these buses.

config MFD_OCELOT_SPI
tristate "Microsemi Ocelot SPI interface"
depends on MFD_OCELOT
depends on SPI_MASTER
select REGMAP_SPI
help
Say yes here to add control to the MFD_OCELOT chips via SPI.

config EZX_PCAP
bool "Motorola EZXPCAP Support"
depends on SPI_MASTER
Expand Down
3 changes: 3 additions & 0 deletions drivers/mfd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o

obj-$(CONFIG_MFD_CORE) += mfd-core.o

obj-$(CONFIG_MFD_OCELOT) += ocelot-core.o
obj-$(CONFIG_MFD_OCELOT_SPI) += ocelot-spi.o

obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o
obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o

Expand Down
165 changes: 165 additions & 0 deletions drivers/mfd/ocelot-core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* MFD core driver for the Ocelot chip family.
*
* The VSC7511, 7512, 7513, and 7514 can be controlled internally via an
* on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is
* intended to be the bus-agnostic glue between, for example, the SPI bus and
* the MFD children.
*
* Copyright 2021 Innovative Advantage Inc.
*
* Author: Colin Foster <colin.foster@in-advantage.com>
*/

#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/regmap.h>

#include <asm/byteorder.h>

#include "ocelot.h"

#define GCB_SOFT_RST (0x0008)

#define SOFT_CHIP_RST (0x1)

static const struct resource vsc7512_gcb_resource = {
.start = 0x71070000,
.end = 0x7107022b,
.name = "devcpu_gcb",
};

static int ocelot_reset(struct ocelot_core *core)
{
int ret;

/*
* Reset the entire chip here to put it into a completely known state.
* Other drivers may want to reset their own subsystems. The register
* self-clears, so one write is all that is needed
*/
ret = regmap_write(core->gcb_regmap, GCB_SOFT_RST, SOFT_CHIP_RST);
if (ret)
return ret;

msleep(100);

/*
* A chip reset will clear the SPI configuration, so it needs to be done
* again before we can access any more registers
*/
ret = ocelot_spi_initialize(core);

return ret;
}

static struct regmap *ocelot_devm_regmap_init(struct ocelot_core *core,
struct device *dev,
const struct resource *res)
{
struct regmap *regmap;

regmap = dev_get_regmap(dev, res->name);
if (!regmap)
regmap = ocelot_spi_devm_get_regmap(core, dev, res);

return regmap;
}

struct regmap *ocelot_get_regmap_from_resource(struct device *dev,
const struct resource *res)
{
struct ocelot_core *core = dev_get_drvdata(dev);

return ocelot_devm_regmap_init(core, dev, res);
}
EXPORT_SYMBOL(ocelot_get_regmap_from_resource);

static const struct resource vsc7512_miim1_resources[] = {
{
.start = 0x710700c0,
.end = 0x710700e3,
.name = "gcb_miim1",
.flags = IORESOURCE_MEM,
},
};

static const struct resource vsc7512_pinctrl_resources[] = {
{
.start = 0x71070034,
.end = 0x7107009f,
.name = "gcb_gpio",
.flags = IORESOURCE_MEM,
},
};

static const struct resource vsc7512_sgpio_resources[] = {
{
.start = 0x710700f8,
.end = 0x710701f7,
.name = "gcb_sio",
.flags = IORESOURCE_MEM,
},
};

static const struct mfd_cell vsc7512_devs[] = {
{
.name = "pinctrl-ocelot",
.of_compatible = "mscc,ocelot-pinctrl",
.num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources),
.resources = vsc7512_pinctrl_resources,
},
{
.name = "pinctrl-sgpio",
.of_compatible = "mscc,ocelot-sgpio",
.num_resources = ARRAY_SIZE(vsc7512_sgpio_resources),
.resources = vsc7512_sgpio_resources,
},
{
.name = "ocelot-miim1",
.of_compatible = "mscc,ocelot-miim",
.num_resources = ARRAY_SIZE(vsc7512_miim1_resources),
.resources = vsc7512_miim1_resources,
},
};

int ocelot_core_init(struct ocelot_core *core)
{
struct device *dev = core->dev;
int ret;

dev_set_drvdata(dev, core);

core->gcb_regmap = ocelot_devm_regmap_init(core, dev,
&vsc7512_gcb_resource);
if (!core->gcb_regmap)
return -ENOMEM;

/* Prepare the chip */
ret = ocelot_reset(core);
if (ret) {
dev_err(dev, "ocelot mfd reset failed with code %d\n", ret);
return ret;
}

ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, vsc7512_devs,
ARRAY_SIZE(vsc7512_devs), NULL, 0, NULL);
if (ret) {
dev_err(dev, "error adding mfd devices\n");
return ret;
}

return 0;
}
EXPORT_SYMBOL(ocelot_core_init);

int ocelot_remove(struct ocelot_core *core)
{
return 0;
}
EXPORT_SYMBOL(ocelot_remove);

MODULE_DESCRIPTION("Ocelot Chip MFD driver");
MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>");
MODULE_LICENSE("GPL v2");

0 comments on commit 17c4774

Please sign in to comment.