14658f2feSArun Ramadoss // SPDX-License-Identifier: GPL-2.0-or-later 24658f2feSArun Ramadoss /* 34658f2feSArun Ramadoss * Microchip ksz series register access through SPI 44658f2feSArun Ramadoss * 54658f2feSArun Ramadoss * Copyright (C) 2017 Microchip Technology Inc. 64658f2feSArun Ramadoss * Tristram Ha <Tristram.Ha@microchip.com> 74658f2feSArun Ramadoss */ 84658f2feSArun Ramadoss 94658f2feSArun Ramadoss #include <asm/unaligned.h> 104658f2feSArun Ramadoss 114658f2feSArun Ramadoss #include <linux/delay.h> 124658f2feSArun Ramadoss #include <linux/kernel.h> 134658f2feSArun Ramadoss #include <linux/module.h> 144658f2feSArun Ramadoss #include <linux/regmap.h> 154658f2feSArun Ramadoss #include <linux/spi/spi.h> 164658f2feSArun Ramadoss 174658f2feSArun Ramadoss #include "ksz_common.h" 184658f2feSArun Ramadoss 194658f2feSArun Ramadoss #define KSZ8795_SPI_ADDR_SHIFT 12 204658f2feSArun Ramadoss #define KSZ8795_SPI_ADDR_ALIGN 3 214658f2feSArun Ramadoss #define KSZ8795_SPI_TURNAROUND_SHIFT 1 224658f2feSArun Ramadoss 234658f2feSArun Ramadoss #define KSZ8863_SPI_ADDR_SHIFT 8 244658f2feSArun Ramadoss #define KSZ8863_SPI_ADDR_ALIGN 8 254658f2feSArun Ramadoss #define KSZ8863_SPI_TURNAROUND_SHIFT 0 264658f2feSArun Ramadoss 274658f2feSArun Ramadoss #define KSZ9477_SPI_ADDR_SHIFT 24 284658f2feSArun Ramadoss #define KSZ9477_SPI_ADDR_ALIGN 3 294658f2feSArun Ramadoss #define KSZ9477_SPI_TURNAROUND_SHIFT 5 304658f2feSArun Ramadoss 314658f2feSArun Ramadoss KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT, 324658f2feSArun Ramadoss KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN); 334658f2feSArun Ramadoss 344658f2feSArun Ramadoss KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT, 354658f2feSArun Ramadoss KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN); 364658f2feSArun Ramadoss 374658f2feSArun Ramadoss KSZ_REGMAP_TABLE(ksz9477, 32, KSZ9477_SPI_ADDR_SHIFT, 384658f2feSArun Ramadoss KSZ9477_SPI_TURNAROUND_SHIFT, KSZ9477_SPI_ADDR_ALIGN); 394658f2feSArun Ramadoss 404658f2feSArun Ramadoss static int ksz_spi_probe(struct spi_device *spi) 414658f2feSArun Ramadoss { 424658f2feSArun Ramadoss const struct regmap_config *regmap_config; 434658f2feSArun Ramadoss const struct ksz_chip_data *chip; 444658f2feSArun Ramadoss struct device *ddev = &spi->dev; 454658f2feSArun Ramadoss struct regmap_config rc; 464658f2feSArun Ramadoss struct ksz_device *dev; 474658f2feSArun Ramadoss int i, ret = 0; 484658f2feSArun Ramadoss 4947d82864SArun Ramadoss dev = ksz_switch_alloc(&spi->dev, spi); 504658f2feSArun Ramadoss if (!dev) 514658f2feSArun Ramadoss return -ENOMEM; 524658f2feSArun Ramadoss 534658f2feSArun Ramadoss chip = device_get_match_data(ddev); 544658f2feSArun Ramadoss if (!chip) 554658f2feSArun Ramadoss return -EINVAL; 564658f2feSArun Ramadoss 574658f2feSArun Ramadoss if (chip->chip_id == KSZ8830_CHIP_ID) 584658f2feSArun Ramadoss regmap_config = ksz8863_regmap_config; 594658f2feSArun Ramadoss else if (chip->chip_id == KSZ8795_CHIP_ID || 604658f2feSArun Ramadoss chip->chip_id == KSZ8794_CHIP_ID || 614658f2feSArun Ramadoss chip->chip_id == KSZ8765_CHIP_ID) 624658f2feSArun Ramadoss regmap_config = ksz8795_regmap_config; 634658f2feSArun Ramadoss else 644658f2feSArun Ramadoss regmap_config = ksz9477_regmap_config; 654658f2feSArun Ramadoss 664658f2feSArun Ramadoss for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { 674658f2feSArun Ramadoss rc = regmap_config[i]; 684658f2feSArun Ramadoss rc.lock_arg = &dev->regmap_mutex; 69ec6ba50cSOleksij Rempel rc.wr_table = chip->wr_table; 70ec6ba50cSOleksij Rempel rc.rd_table = chip->rd_table; 714658f2feSArun Ramadoss dev->regmap[i] = devm_regmap_init_spi(spi, &rc); 72ec6ba50cSOleksij Rempel 734658f2feSArun Ramadoss if (IS_ERR(dev->regmap[i])) { 744658f2feSArun Ramadoss ret = PTR_ERR(dev->regmap[i]); 754658f2feSArun Ramadoss dev_err(&spi->dev, 764658f2feSArun Ramadoss "Failed to initialize regmap%i: %d\n", 774658f2feSArun Ramadoss regmap_config[i].val_bits, ret); 784658f2feSArun Ramadoss return ret; 794658f2feSArun Ramadoss } 804658f2feSArun Ramadoss } 814658f2feSArun Ramadoss 824658f2feSArun Ramadoss if (spi->dev.platform_data) 834658f2feSArun Ramadoss dev->pdata = spi->dev.platform_data; 844658f2feSArun Ramadoss 854658f2feSArun Ramadoss /* setup spi */ 864658f2feSArun Ramadoss spi->mode = SPI_MODE_3; 874658f2feSArun Ramadoss ret = spi_setup(spi); 884658f2feSArun Ramadoss if (ret) 894658f2feSArun Ramadoss return ret; 904658f2feSArun Ramadoss 91c9cd961cSArun Ramadoss dev->irq = spi->irq; 92c9cd961cSArun Ramadoss 934658f2feSArun Ramadoss ret = ksz_switch_register(dev); 944658f2feSArun Ramadoss 954658f2feSArun Ramadoss /* Main DSA driver may not be started yet. */ 964658f2feSArun Ramadoss if (ret) 974658f2feSArun Ramadoss return ret; 984658f2feSArun Ramadoss 994658f2feSArun Ramadoss spi_set_drvdata(spi, dev); 1004658f2feSArun Ramadoss 1014658f2feSArun Ramadoss return 0; 1024658f2feSArun Ramadoss } 1034658f2feSArun Ramadoss 1044658f2feSArun Ramadoss static void ksz_spi_remove(struct spi_device *spi) 1054658f2feSArun Ramadoss { 1064658f2feSArun Ramadoss struct ksz_device *dev = spi_get_drvdata(spi); 1074658f2feSArun Ramadoss 1084658f2feSArun Ramadoss if (dev) 1094658f2feSArun Ramadoss ksz_switch_remove(dev); 1104658f2feSArun Ramadoss } 1114658f2feSArun Ramadoss 1124658f2feSArun Ramadoss static void ksz_spi_shutdown(struct spi_device *spi) 1134658f2feSArun Ramadoss { 1144658f2feSArun Ramadoss struct ksz_device *dev = spi_get_drvdata(spi); 1154658f2feSArun Ramadoss 1164658f2feSArun Ramadoss if (!dev) 1174658f2feSArun Ramadoss return; 1184658f2feSArun Ramadoss 1194658f2feSArun Ramadoss if (dev->dev_ops->reset) 1204658f2feSArun Ramadoss dev->dev_ops->reset(dev); 1214658f2feSArun Ramadoss 1224658f2feSArun Ramadoss dsa_switch_shutdown(dev->ds); 1234658f2feSArun Ramadoss 1244658f2feSArun Ramadoss spi_set_drvdata(spi, NULL); 1254658f2feSArun Ramadoss } 1264658f2feSArun Ramadoss 1274658f2feSArun Ramadoss static const struct of_device_id ksz_dt_ids[] = { 1284658f2feSArun Ramadoss { 1294658f2feSArun Ramadoss .compatible = "microchip,ksz8765", 1304658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8765] 1314658f2feSArun Ramadoss }, 1324658f2feSArun Ramadoss { 1334658f2feSArun Ramadoss .compatible = "microchip,ksz8794", 1344658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8794] 1354658f2feSArun Ramadoss }, 1364658f2feSArun Ramadoss { 1374658f2feSArun Ramadoss .compatible = "microchip,ksz8795", 1384658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8795] 1394658f2feSArun Ramadoss }, 1404658f2feSArun Ramadoss { 1414658f2feSArun Ramadoss .compatible = "microchip,ksz8863", 1424658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8830] 1434658f2feSArun Ramadoss }, 1444658f2feSArun Ramadoss { 1454658f2feSArun Ramadoss .compatible = "microchip,ksz8873", 1464658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8830] 1474658f2feSArun Ramadoss }, 1484658f2feSArun Ramadoss { 1494658f2feSArun Ramadoss .compatible = "microchip,ksz9477", 1504658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9477] 1514658f2feSArun Ramadoss }, 1524658f2feSArun Ramadoss { 1532eb3ff3cSRomain Naour .compatible = "microchip,ksz9896", 1542eb3ff3cSRomain Naour .data = &ksz_switch_chips[KSZ9896] 1552eb3ff3cSRomain Naour }, 1562eb3ff3cSRomain Naour { 1574658f2feSArun Ramadoss .compatible = "microchip,ksz9897", 1584658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9897] 1594658f2feSArun Ramadoss }, 1604658f2feSArun Ramadoss { 1614658f2feSArun Ramadoss .compatible = "microchip,ksz9893", 1624658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9893] 1634658f2feSArun Ramadoss }, 1644658f2feSArun Ramadoss { 1654658f2feSArun Ramadoss .compatible = "microchip,ksz9563", 166*ef912fe4SRakesh Sankaranarayanan .data = &ksz_switch_chips[KSZ9563] 1674658f2feSArun Ramadoss }, 1684658f2feSArun Ramadoss { 1694658f2feSArun Ramadoss .compatible = "microchip,ksz8563", 170b4490809SOleksij Rempel .data = &ksz_switch_chips[KSZ8563] 1714658f2feSArun Ramadoss }, 1724658f2feSArun Ramadoss { 1734658f2feSArun Ramadoss .compatible = "microchip,ksz9567", 1744658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9567] 1754658f2feSArun Ramadoss }, 176c8fac9d0SArun Ramadoss { 177c8fac9d0SArun Ramadoss .compatible = "microchip,lan9370", 178c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9370] 179c8fac9d0SArun Ramadoss }, 180c8fac9d0SArun Ramadoss { 181c8fac9d0SArun Ramadoss .compatible = "microchip,lan9371", 182c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9371] 183c8fac9d0SArun Ramadoss }, 184c8fac9d0SArun Ramadoss { 185c8fac9d0SArun Ramadoss .compatible = "microchip,lan9372", 186c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9372] 187c8fac9d0SArun Ramadoss }, 188c8fac9d0SArun Ramadoss { 189c8fac9d0SArun Ramadoss .compatible = "microchip,lan9373", 190c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9373] 191c8fac9d0SArun Ramadoss }, 192c8fac9d0SArun Ramadoss { 193c8fac9d0SArun Ramadoss .compatible = "microchip,lan9374", 194c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9374] 195c8fac9d0SArun Ramadoss }, 1964658f2feSArun Ramadoss {}, 1974658f2feSArun Ramadoss }; 1984658f2feSArun Ramadoss MODULE_DEVICE_TABLE(of, ksz_dt_ids); 1994658f2feSArun Ramadoss 2004658f2feSArun Ramadoss static const struct spi_device_id ksz_spi_ids[] = { 2014658f2feSArun Ramadoss { "ksz8765" }, 2024658f2feSArun Ramadoss { "ksz8794" }, 2034658f2feSArun Ramadoss { "ksz8795" }, 2044658f2feSArun Ramadoss { "ksz8863" }, 2054658f2feSArun Ramadoss { "ksz8873" }, 2064658f2feSArun Ramadoss { "ksz9477" }, 2072eb3ff3cSRomain Naour { "ksz9896" }, 2084658f2feSArun Ramadoss { "ksz9897" }, 2094658f2feSArun Ramadoss { "ksz9893" }, 2104658f2feSArun Ramadoss { "ksz9563" }, 2114658f2feSArun Ramadoss { "ksz8563" }, 2124658f2feSArun Ramadoss { "ksz9567" }, 213c8fac9d0SArun Ramadoss { "lan9370" }, 214c8fac9d0SArun Ramadoss { "lan9371" }, 215c8fac9d0SArun Ramadoss { "lan9372" }, 216c8fac9d0SArun Ramadoss { "lan9373" }, 217c8fac9d0SArun Ramadoss { "lan9374" }, 2184658f2feSArun Ramadoss { }, 2194658f2feSArun Ramadoss }; 2204658f2feSArun Ramadoss MODULE_DEVICE_TABLE(spi, ksz_spi_ids); 2214658f2feSArun Ramadoss 2224658f2feSArun Ramadoss static struct spi_driver ksz_spi_driver = { 2234658f2feSArun Ramadoss .driver = { 2244658f2feSArun Ramadoss .name = "ksz-switch", 2254658f2feSArun Ramadoss .owner = THIS_MODULE, 226da53af8cSArun Ramadoss .of_match_table = ksz_dt_ids, 2274658f2feSArun Ramadoss }, 2284658f2feSArun Ramadoss .id_table = ksz_spi_ids, 2294658f2feSArun Ramadoss .probe = ksz_spi_probe, 2304658f2feSArun Ramadoss .remove = ksz_spi_remove, 2314658f2feSArun Ramadoss .shutdown = ksz_spi_shutdown, 2324658f2feSArun Ramadoss }; 2334658f2feSArun Ramadoss 2344658f2feSArun Ramadoss module_spi_driver(ksz_spi_driver); 2354658f2feSArun Ramadoss 2364658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9477"); 2372eb3ff3cSRomain Naour MODULE_ALIAS("spi:ksz9896"); 2384658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9897"); 2394658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9893"); 2404658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9563"); 2414658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz8563"); 2424658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9567"); 243c8fac9d0SArun Ramadoss MODULE_ALIAS("spi:lan937x"); 2444658f2feSArun Ramadoss MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); 2454658f2feSArun Ramadoss MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver"); 2464658f2feSArun Ramadoss MODULE_LICENSE("GPL"); 247