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 91*c9cd961cSArun Ramadoss dev->irq = spi->irq; 92*c9cd961cSArun 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 spi_set_drvdata(spi, NULL); 1124658f2feSArun Ramadoss } 1134658f2feSArun Ramadoss 1144658f2feSArun Ramadoss static void ksz_spi_shutdown(struct spi_device *spi) 1154658f2feSArun Ramadoss { 1164658f2feSArun Ramadoss struct ksz_device *dev = spi_get_drvdata(spi); 1174658f2feSArun Ramadoss 1184658f2feSArun Ramadoss if (!dev) 1194658f2feSArun Ramadoss return; 1204658f2feSArun Ramadoss 1214658f2feSArun Ramadoss if (dev->dev_ops->reset) 1224658f2feSArun Ramadoss dev->dev_ops->reset(dev); 1234658f2feSArun Ramadoss 1244658f2feSArun Ramadoss dsa_switch_shutdown(dev->ds); 1254658f2feSArun Ramadoss 1264658f2feSArun Ramadoss spi_set_drvdata(spi, NULL); 1274658f2feSArun Ramadoss } 1284658f2feSArun Ramadoss 1294658f2feSArun Ramadoss static const struct of_device_id ksz_dt_ids[] = { 1304658f2feSArun Ramadoss { 1314658f2feSArun Ramadoss .compatible = "microchip,ksz8765", 1324658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8765] 1334658f2feSArun Ramadoss }, 1344658f2feSArun Ramadoss { 1354658f2feSArun Ramadoss .compatible = "microchip,ksz8794", 1364658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8794] 1374658f2feSArun Ramadoss }, 1384658f2feSArun Ramadoss { 1394658f2feSArun Ramadoss .compatible = "microchip,ksz8795", 1404658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8795] 1414658f2feSArun Ramadoss }, 1424658f2feSArun Ramadoss { 1434658f2feSArun Ramadoss .compatible = "microchip,ksz8863", 1444658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8830] 1454658f2feSArun Ramadoss }, 1464658f2feSArun Ramadoss { 1474658f2feSArun Ramadoss .compatible = "microchip,ksz8873", 1484658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ8830] 1494658f2feSArun Ramadoss }, 1504658f2feSArun Ramadoss { 1514658f2feSArun Ramadoss .compatible = "microchip,ksz9477", 1524658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9477] 1534658f2feSArun Ramadoss }, 1544658f2feSArun Ramadoss { 1554658f2feSArun Ramadoss .compatible = "microchip,ksz9897", 1564658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9897] 1574658f2feSArun Ramadoss }, 1584658f2feSArun Ramadoss { 1594658f2feSArun Ramadoss .compatible = "microchip,ksz9893", 1604658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9893] 1614658f2feSArun Ramadoss }, 1624658f2feSArun Ramadoss { 1634658f2feSArun Ramadoss .compatible = "microchip,ksz9563", 1644658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9893] 1654658f2feSArun Ramadoss }, 1664658f2feSArun Ramadoss { 1674658f2feSArun Ramadoss .compatible = "microchip,ksz8563", 168b4490809SOleksij Rempel .data = &ksz_switch_chips[KSZ8563] 1694658f2feSArun Ramadoss }, 1704658f2feSArun Ramadoss { 1714658f2feSArun Ramadoss .compatible = "microchip,ksz9567", 1724658f2feSArun Ramadoss .data = &ksz_switch_chips[KSZ9567] 1734658f2feSArun Ramadoss }, 174c8fac9d0SArun Ramadoss { 175c8fac9d0SArun Ramadoss .compatible = "microchip,lan9370", 176c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9370] 177c8fac9d0SArun Ramadoss }, 178c8fac9d0SArun Ramadoss { 179c8fac9d0SArun Ramadoss .compatible = "microchip,lan9371", 180c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9371] 181c8fac9d0SArun Ramadoss }, 182c8fac9d0SArun Ramadoss { 183c8fac9d0SArun Ramadoss .compatible = "microchip,lan9372", 184c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9372] 185c8fac9d0SArun Ramadoss }, 186c8fac9d0SArun Ramadoss { 187c8fac9d0SArun Ramadoss .compatible = "microchip,lan9373", 188c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9373] 189c8fac9d0SArun Ramadoss }, 190c8fac9d0SArun Ramadoss { 191c8fac9d0SArun Ramadoss .compatible = "microchip,lan9374", 192c8fac9d0SArun Ramadoss .data = &ksz_switch_chips[LAN9374] 193c8fac9d0SArun Ramadoss }, 1944658f2feSArun Ramadoss {}, 1954658f2feSArun Ramadoss }; 1964658f2feSArun Ramadoss MODULE_DEVICE_TABLE(of, ksz_dt_ids); 1974658f2feSArun Ramadoss 1984658f2feSArun Ramadoss static const struct spi_device_id ksz_spi_ids[] = { 1994658f2feSArun Ramadoss { "ksz8765" }, 2004658f2feSArun Ramadoss { "ksz8794" }, 2014658f2feSArun Ramadoss { "ksz8795" }, 2024658f2feSArun Ramadoss { "ksz8863" }, 2034658f2feSArun Ramadoss { "ksz8873" }, 2044658f2feSArun Ramadoss { "ksz9477" }, 2054658f2feSArun Ramadoss { "ksz9897" }, 2064658f2feSArun Ramadoss { "ksz9893" }, 2074658f2feSArun Ramadoss { "ksz9563" }, 2084658f2feSArun Ramadoss { "ksz8563" }, 2094658f2feSArun Ramadoss { "ksz9567" }, 210c8fac9d0SArun Ramadoss { "lan9370" }, 211c8fac9d0SArun Ramadoss { "lan9371" }, 212c8fac9d0SArun Ramadoss { "lan9372" }, 213c8fac9d0SArun Ramadoss { "lan9373" }, 214c8fac9d0SArun Ramadoss { "lan9374" }, 2154658f2feSArun Ramadoss { }, 2164658f2feSArun Ramadoss }; 2174658f2feSArun Ramadoss MODULE_DEVICE_TABLE(spi, ksz_spi_ids); 2184658f2feSArun Ramadoss 2194658f2feSArun Ramadoss static struct spi_driver ksz_spi_driver = { 2204658f2feSArun Ramadoss .driver = { 2214658f2feSArun Ramadoss .name = "ksz-switch", 2224658f2feSArun Ramadoss .owner = THIS_MODULE, 223da53af8cSArun Ramadoss .of_match_table = ksz_dt_ids, 2244658f2feSArun Ramadoss }, 2254658f2feSArun Ramadoss .id_table = ksz_spi_ids, 2264658f2feSArun Ramadoss .probe = ksz_spi_probe, 2274658f2feSArun Ramadoss .remove = ksz_spi_remove, 2284658f2feSArun Ramadoss .shutdown = ksz_spi_shutdown, 2294658f2feSArun Ramadoss }; 2304658f2feSArun Ramadoss 2314658f2feSArun Ramadoss module_spi_driver(ksz_spi_driver); 2324658f2feSArun Ramadoss 2334658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9477"); 2344658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9897"); 2354658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9893"); 2364658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9563"); 2374658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz8563"); 2384658f2feSArun Ramadoss MODULE_ALIAS("spi:ksz9567"); 239c8fac9d0SArun Ramadoss MODULE_ALIAS("spi:lan937x"); 2404658f2feSArun Ramadoss MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); 2414658f2feSArun Ramadoss MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver"); 2424658f2feSArun Ramadoss MODULE_LICENSE("GPL"); 243