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