1 // SPDX-License-Identifier: GPL-2.0+
3 * MFD driver for Airoha AN8855 Switch
6 #include <linux/mfd/airoha-an8855-mfd.h>
7 #include <linux/mfd/core.h>
8 #include <linux/mdio.h>
9 #include <linux/module.h>
10 #include <linux/phy.h>
11 #include <linux/regmap.h>
13 static const struct mfd_cell an8855_mfd_devs
[] = {
15 .name
= "an8855-efuse",
16 .of_compatible
= "airoha,an8855-efuse",
18 .name
= "an8855-switch",
19 .of_compatible
= "airoha,an8855-switch",
21 .name
= "an8855-mdio",
22 .of_compatible
= "airoha,an8855-mdio",
26 int an8855_mii_set_page(struct an8855_mfd_priv
*priv
, u8 phy_id
,
27 u8 page
) __must_hold(&priv
->bus
->mdio_lock
)
29 struct mii_bus
*bus
= priv
->bus
;
32 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PHY_SELECT_PAGE
, page
);
34 dev_err_ratelimited(&bus
->dev
,
35 "failed to set an8855 mii page\n");
37 /* Cache current page if next mii read/write is for switch */
38 priv
->current_page
= page
;
39 return ret
< 0 ? ret
: 0;
41 EXPORT_SYMBOL_GPL(an8855_mii_set_page
);
43 static int an8855_mii_read32(struct mii_bus
*bus
, u8 phy_id
, u32 reg
,
44 u32
*val
) __must_hold(&bus
->mdio_lock
)
48 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_MODE
,
49 AN8855_PBUS_MODE_ADDR_FIXED
);
53 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_RD_ADDR_HIGH
,
57 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_RD_ADDR_LOW
,
62 hi
= __mdiobus_read(bus
, phy_id
, AN8855_PBUS_RD_DATA_HIGH
);
67 lo
= __mdiobus_read(bus
, phy_id
, AN8855_PBUS_RD_DATA_LOW
);
73 *val
= ((u16
)hi
<< 16) | ((u16
)lo
& 0xffff);
77 dev_err_ratelimited(&bus
->dev
,
78 "failed to read an8855 register\n");
82 static int an8855_regmap_read(void *ctx
, uint32_t reg
, uint32_t *val
)
84 struct an8855_mfd_priv
*priv
= ctx
;
85 struct mii_bus
*bus
= priv
->bus
;
86 u16 addr
= priv
->switch_addr
;
89 mutex_lock_nested(&bus
->mdio_lock
, MDIO_MUTEX_NESTED
);
90 ret
= an8855_mii_set_page(priv
, addr
, AN8855_PHY_PAGE_EXTENDED_4
);
94 ret
= an8855_mii_read32(bus
, addr
, reg
, val
);
97 mutex_unlock(&bus
->mdio_lock
);
99 return ret
< 0 ? ret
: 0;
102 static int an8855_mii_write32(struct mii_bus
*bus
, u8 phy_id
, u32 reg
,
103 u32 val
) __must_hold(&bus
->mdio_lock
)
107 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_MODE
,
108 AN8855_PBUS_MODE_ADDR_FIXED
);
112 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_WR_ADDR_HIGH
,
116 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_WR_ADDR_LOW
,
121 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_WR_DATA_HIGH
,
125 ret
= __mdiobus_write(bus
, phy_id
, AN8855_PBUS_WR_DATA_LOW
,
132 dev_err_ratelimited(&bus
->dev
,
133 "failed to write an8855 register\n");
138 an8855_regmap_write(void *ctx
, uint32_t reg
, uint32_t val
)
140 struct an8855_mfd_priv
*priv
= ctx
;
141 struct mii_bus
*bus
= priv
->bus
;
142 u16 addr
= priv
->switch_addr
;
145 mutex_lock_nested(&bus
->mdio_lock
, MDIO_MUTEX_NESTED
);
146 ret
= an8855_mii_set_page(priv
, addr
, AN8855_PHY_PAGE_EXTENDED_4
);
150 ret
= an8855_mii_write32(bus
, addr
, reg
, val
);
153 mutex_unlock(&bus
->mdio_lock
);
155 return ret
< 0 ? ret
: 0;
158 static int an8855_regmap_update_bits(void *ctx
, uint32_t reg
, uint32_t mask
,
161 struct an8855_mfd_priv
*priv
= ctx
;
162 struct mii_bus
*bus
= priv
->bus
;
163 u16 addr
= priv
->switch_addr
;
167 mutex_lock_nested(&bus
->mdio_lock
, MDIO_MUTEX_NESTED
);
168 ret
= an8855_mii_set_page(priv
, addr
, AN8855_PHY_PAGE_EXTENDED_4
);
172 ret
= an8855_mii_read32(bus
, addr
, reg
, &val
);
178 ret
= an8855_mii_write32(bus
, addr
, reg
, val
);
181 mutex_unlock(&bus
->mdio_lock
);
183 return ret
< 0 ? ret
: 0;
186 static const struct regmap_range an8855_readable_ranges
[] = {
187 regmap_reg_range(0x10000000, 0x10000fff), /* SCU */
188 regmap_reg_range(0x10001000, 0x10001fff), /* RBUS */
189 regmap_reg_range(0x10002000, 0x10002fff), /* MCU */
190 regmap_reg_range(0x10005000, 0x10005fff), /* SYS SCU */
191 regmap_reg_range(0x10007000, 0x10007fff), /* I2C Slave */
192 regmap_reg_range(0x10008000, 0x10008fff), /* I2C Master */
193 regmap_reg_range(0x10009000, 0x10009fff), /* PDMA */
194 regmap_reg_range(0x1000a100, 0x1000a2ff), /* General Purpose Timer */
195 regmap_reg_range(0x1000a200, 0x1000a2ff), /* GPU timer */
196 regmap_reg_range(0x1000a300, 0x1000a3ff), /* GPIO */
197 regmap_reg_range(0x1000a400, 0x1000a5ff), /* EFUSE */
198 regmap_reg_range(0x1000c000, 0x1000cfff), /* GDMP CSR */
199 regmap_reg_range(0x10010000, 0x1001ffff), /* GDMP SRAM */
200 regmap_reg_range(0x10200000, 0x10203fff), /* Switch - ARL Global */
201 regmap_reg_range(0x10204000, 0x10207fff), /* Switch - BMU */
202 regmap_reg_range(0x10208000, 0x1020bfff), /* Switch - ARL Port */
203 regmap_reg_range(0x1020c000, 0x1020cfff), /* Switch - SCH */
204 regmap_reg_range(0x10210000, 0x10213fff), /* Switch - MAC */
205 regmap_reg_range(0x10214000, 0x10217fff), /* Switch - MIB */
206 regmap_reg_range(0x10218000, 0x1021bfff), /* Switch - Port Control */
207 regmap_reg_range(0x1021c000, 0x1021ffff), /* Switch - TOP */
208 regmap_reg_range(0x10220000, 0x1022ffff), /* SerDes */
209 regmap_reg_range(0x10286000, 0x10286fff), /* RG Batcher */
210 regmap_reg_range(0x1028c000, 0x1028ffff), /* ETHER_SYS */
211 regmap_reg_range(0x30000000, 0x37ffffff), /* I2C EEPROM */
212 regmap_reg_range(0x38000000, 0x3fffffff), /* BOOT_ROM */
213 regmap_reg_range(0xa0000000, 0xbfffffff), /* GPHY */
216 static const struct regmap_access_table an8855_readable_table
= {
217 .yes_ranges
= an8855_readable_ranges
,
218 .n_yes_ranges
= ARRAY_SIZE(an8855_readable_ranges
),
221 static const struct regmap_config an8855_regmap_config
= {
225 .max_register
= 0xbfffffff,
226 .reg_read
= an8855_regmap_read
,
227 .reg_write
= an8855_regmap_write
,
228 .reg_update_bits
= an8855_regmap_update_bits
,
229 .disable_locking
= true,
230 .rd_table
= &an8855_readable_table
,
233 static int an8855_mfd_probe(struct mdio_device
*mdiodev
)
235 struct an8855_mfd_priv
*priv
;
236 struct regmap
*regmap
;
238 priv
= devm_kzalloc(&mdiodev
->dev
, sizeof(*priv
), GFP_KERNEL
);
242 priv
->bus
= mdiodev
->bus
;
243 priv
->dev
= &mdiodev
->dev
;
244 priv
->switch_addr
= mdiodev
->addr
;
245 /* no DMA for mdiobus, mute warning for DMA mask not set */
246 priv
->dev
->dma_mask
= &priv
->dev
->coherent_dma_mask
;
248 regmap
= devm_regmap_init(priv
->dev
, NULL
, priv
,
249 &an8855_regmap_config
);
251 dev_err_probe(priv
->dev
, PTR_ERR(priv
->dev
),
252 "regmap initialization failed\n");
254 dev_set_drvdata(&mdiodev
->dev
, priv
);
256 return devm_mfd_add_devices(priv
->dev
, PLATFORM_DEVID_AUTO
, an8855_mfd_devs
,
257 ARRAY_SIZE(an8855_mfd_devs
), NULL
, 0,
261 static const struct of_device_id an8855_mfd_of_match
[] = {
262 { .compatible
= "airoha,an8855-mfd" },
265 MODULE_DEVICE_TABLE(of
, an8855_mfd_of_match
);
267 static struct mdio_driver an8855_mfd_driver
= {
268 .probe
= an8855_mfd_probe
,
271 .of_match_table
= an8855_mfd_of_match
,
274 mdio_module_driver(an8855_mfd_driver
);
276 MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
277 MODULE_DESCRIPTION("Driver for Airoha AN8855 MFD");
278 MODULE_LICENSE("GPL");