block: fix hctx checks for batch allocation
[platform/kernel/linux-starfive.git] / drivers / mfd / ocelot-core.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 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);