ksz8795_spi.c (3778B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Microchip KSZ8795 series register access through SPI 4 * 5 * Copyright (C) 2017 Microchip Technology Inc. 6 * Tristram Ha <Tristram.Ha@microchip.com> 7 */ 8 9#include <asm/unaligned.h> 10 11#include <linux/delay.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/regmap.h> 15#include <linux/spi/spi.h> 16 17#include "ksz8.h" 18#include "ksz_common.h" 19 20#define KSZ8795_SPI_ADDR_SHIFT 12 21#define KSZ8795_SPI_ADDR_ALIGN 3 22#define KSZ8795_SPI_TURNAROUND_SHIFT 1 23 24#define KSZ8863_SPI_ADDR_SHIFT 8 25#define KSZ8863_SPI_ADDR_ALIGN 8 26#define KSZ8863_SPI_TURNAROUND_SHIFT 0 27 28KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT, 29 KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN); 30 31KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT, 32 KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN); 33 34static int ksz8795_spi_probe(struct spi_device *spi) 35{ 36 const struct regmap_config *regmap_config; 37 const struct ksz_chip_data *chip; 38 struct device *ddev = &spi->dev; 39 struct regmap_config rc; 40 struct ksz_device *dev; 41 struct ksz8 *ksz8; 42 int i, ret = 0; 43 44 ksz8 = devm_kzalloc(&spi->dev, sizeof(struct ksz8), GFP_KERNEL); 45 if (!ksz8) 46 return -ENOMEM; 47 48 ksz8->priv = spi; 49 50 dev = ksz_switch_alloc(&spi->dev, ksz8); 51 if (!dev) 52 return -ENOMEM; 53 54 chip = device_get_match_data(ddev); 55 if (!chip) 56 return -EINVAL; 57 58 if (chip->chip_id == KSZ8830_CHIP_ID) 59 regmap_config = ksz8863_regmap_config; 60 else 61 regmap_config = ksz8795_regmap_config; 62 63 for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { 64 rc = regmap_config[i]; 65 rc.lock_arg = &dev->regmap_mutex; 66 dev->regmap[i] = devm_regmap_init_spi(spi, &rc); 67 if (IS_ERR(dev->regmap[i])) { 68 ret = PTR_ERR(dev->regmap[i]); 69 dev_err(&spi->dev, 70 "Failed to initialize regmap%i: %d\n", 71 regmap_config[i].val_bits, ret); 72 return ret; 73 } 74 } 75 76 if (spi->dev.platform_data) 77 dev->pdata = spi->dev.platform_data; 78 79 /* setup spi */ 80 spi->mode = SPI_MODE_3; 81 ret = spi_setup(spi); 82 if (ret) 83 return ret; 84 85 ret = ksz8_switch_register(dev); 86 87 /* Main DSA driver may not be started yet. */ 88 if (ret) 89 return ret; 90 91 spi_set_drvdata(spi, dev); 92 93 return 0; 94} 95 96static void ksz8795_spi_remove(struct spi_device *spi) 97{ 98 struct ksz_device *dev = spi_get_drvdata(spi); 99 100 if (dev) 101 ksz_switch_remove(dev); 102 103 spi_set_drvdata(spi, NULL); 104} 105 106static void ksz8795_spi_shutdown(struct spi_device *spi) 107{ 108 struct ksz_device *dev = spi_get_drvdata(spi); 109 110 if (!dev) 111 return; 112 113 if (dev->dev_ops->shutdown) 114 dev->dev_ops->shutdown(dev); 115 116 dsa_switch_shutdown(dev->ds); 117 118 spi_set_drvdata(spi, NULL); 119} 120 121static const struct of_device_id ksz8795_dt_ids[] = { 122 { 123 .compatible = "microchip,ksz8765", 124 .data = &ksz_switch_chips[KSZ8765] 125 }, 126 { 127 .compatible = "microchip,ksz8794", 128 .data = &ksz_switch_chips[KSZ8794] 129 }, 130 { 131 .compatible = "microchip,ksz8795", 132 .data = &ksz_switch_chips[KSZ8795] 133 }, 134 { 135 .compatible = "microchip,ksz8863", 136 .data = &ksz_switch_chips[KSZ8830] 137 }, 138 { 139 .compatible = "microchip,ksz8873", 140 .data = &ksz_switch_chips[KSZ8830] 141 }, 142 {}, 143}; 144MODULE_DEVICE_TABLE(of, ksz8795_dt_ids); 145 146static const struct spi_device_id ksz8795_spi_ids[] = { 147 { "ksz8765" }, 148 { "ksz8794" }, 149 { "ksz8795" }, 150 { "ksz8863" }, 151 { "ksz8873" }, 152 { }, 153}; 154MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); 155 156static struct spi_driver ksz8795_spi_driver = { 157 .driver = { 158 .name = "ksz8795-switch", 159 .owner = THIS_MODULE, 160 .of_match_table = of_match_ptr(ksz8795_dt_ids), 161 }, 162 .id_table = ksz8795_spi_ids, 163 .probe = ksz8795_spi_probe, 164 .remove = ksz8795_spi_remove, 165 .shutdown = ksz8795_spi_shutdown, 166}; 167 168module_spi_driver(ksz8795_spi_driver); 169 170MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); 171MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch SPI Driver"); 172MODULE_LICENSE("GPL");