1 /* 2 * Microchip KSZ series register access through SPI 3 * 4 * Copyright (C) 2017 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <asm/unaligned.h> 20 21 #include <linux/delay.h> 22 #include <linux/kernel.h> 23 #include <linux/module.h> 24 #include <linux/spi/spi.h> 25 26 #include "ksz_priv.h" 27 28 /* SPI frame opcodes */ 29 #define KS_SPIOP_RD 3 30 #define KS_SPIOP_WR 2 31 32 #define SPI_ADDR_SHIFT 24 33 #define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1) 34 #define SPI_TURNAROUND_SHIFT 5 35 36 static int ksz_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, 37 unsigned int len) 38 { 39 u32 txbuf; 40 int ret; 41 42 txbuf = reg & SPI_ADDR_MASK; 43 txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT; 44 txbuf <<= SPI_TURNAROUND_SHIFT; 45 txbuf = cpu_to_be32(txbuf); 46 47 ret = spi_write_then_read(spi, &txbuf, 4, val, len); 48 return ret; 49 } 50 51 static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, 52 unsigned int len) 53 { 54 struct spi_device *spi = dev->priv; 55 56 return ksz_spi_read_reg(spi, reg, data, len); 57 } 58 59 static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) 60 { 61 return ksz_spi_read(dev, reg, val, 1); 62 } 63 64 static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) 65 { 66 int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); 67 68 if (!ret) 69 *val = be16_to_cpu(*val); 70 71 return ret; 72 } 73 74 static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val) 75 { 76 int ret; 77 78 *val = 0; 79 ret = ksz_spi_read(dev, reg, (u8 *)val, 3); 80 if (!ret) { 81 *val = be32_to_cpu(*val); 82 /* convert to 24bit */ 83 *val >>= 8; 84 } 85 86 return ret; 87 } 88 89 static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) 90 { 91 int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); 92 93 if (!ret) 94 *val = be32_to_cpu(*val); 95 96 return ret; 97 } 98 99 static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, 100 unsigned int len) 101 { 102 u32 txbuf; 103 u8 data[12]; 104 int i; 105 106 txbuf = reg & SPI_ADDR_MASK; 107 txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT); 108 txbuf <<= SPI_TURNAROUND_SHIFT; 109 txbuf = cpu_to_be32(txbuf); 110 111 data[0] = txbuf & 0xFF; 112 data[1] = (txbuf & 0xFF00) >> 8; 113 data[2] = (txbuf & 0xFF0000) >> 16; 114 data[3] = (txbuf & 0xFF000000) >> 24; 115 for (i = 0; i < len; i++) 116 data[i + 4] = val[i]; 117 118 return spi_write(spi, &data, 4 + len); 119 } 120 121 static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) 122 { 123 struct spi_device *spi = dev->priv; 124 125 return ksz_spi_write_reg(spi, reg, &value, 1); 126 } 127 128 static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) 129 { 130 struct spi_device *spi = dev->priv; 131 132 value = cpu_to_be16(value); 133 return ksz_spi_write_reg(spi, reg, (u8 *)&value, 2); 134 } 135 136 static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value) 137 { 138 struct spi_device *spi = dev->priv; 139 140 /* make it to big endian 24bit from MSB */ 141 value <<= 8; 142 value = cpu_to_be32(value); 143 return ksz_spi_write_reg(spi, reg, (u8 *)&value, 3); 144 } 145 146 static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) 147 { 148 struct spi_device *spi = dev->priv; 149 150 value = cpu_to_be32(value); 151 return ksz_spi_write_reg(spi, reg, (u8 *)&value, 4); 152 } 153 154 static const struct ksz_io_ops ksz_spi_ops = { 155 .read8 = ksz_spi_read8, 156 .read16 = ksz_spi_read16, 157 .read24 = ksz_spi_read24, 158 .read32 = ksz_spi_read32, 159 .write8 = ksz_spi_write8, 160 .write16 = ksz_spi_write16, 161 .write24 = ksz_spi_write24, 162 .write32 = ksz_spi_write32, 163 }; 164 165 static int ksz_spi_probe(struct spi_device *spi) 166 { 167 struct ksz_device *dev; 168 int ret; 169 170 dev = ksz_switch_alloc(&spi->dev, &ksz_spi_ops, spi); 171 if (!dev) 172 return -ENOMEM; 173 174 if (spi->dev.platform_data) 175 dev->pdata = spi->dev.platform_data; 176 177 ret = ksz_switch_register(dev); 178 if (ret) 179 return ret; 180 181 spi_set_drvdata(spi, dev); 182 183 return 0; 184 } 185 186 static int ksz_spi_remove(struct spi_device *spi) 187 { 188 struct ksz_device *dev = spi_get_drvdata(spi); 189 190 if (dev) 191 ksz_switch_remove(dev); 192 193 return 0; 194 } 195 196 static const struct of_device_id ksz_dt_ids[] = { 197 { .compatible = "microchip,ksz9477" }, 198 {}, 199 }; 200 MODULE_DEVICE_TABLE(of, ksz_dt_ids); 201 202 static struct spi_driver ksz_spi_driver = { 203 .driver = { 204 .name = "ksz9477-switch", 205 .owner = THIS_MODULE, 206 .of_match_table = of_match_ptr(ksz_dt_ids), 207 }, 208 .probe = ksz_spi_probe, 209 .remove = ksz_spi_remove, 210 }; 211 212 module_spi_driver(ksz_spi_driver); 213 214 MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); 215 MODULE_DESCRIPTION("Microchip KSZ Series Switch SPI access Driver"); 216 MODULE_LICENSE("GPL"); 217