1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Microchip ksz 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 "ksz_common.h" |
18 | |
19 | #define KSZ8795_SPI_ADDR_SHIFT 12 |
20 | #define KSZ8795_SPI_ADDR_ALIGN 3 |
21 | #define KSZ8795_SPI_TURNAROUND_SHIFT 1 |
22 | |
23 | #define KSZ8863_SPI_ADDR_SHIFT 8 |
24 | #define KSZ8863_SPI_ADDR_ALIGN 8 |
25 | #define KSZ8863_SPI_TURNAROUND_SHIFT 0 |
26 | |
27 | #define KSZ9477_SPI_ADDR_SHIFT 24 |
28 | #define KSZ9477_SPI_ADDR_ALIGN 3 |
29 | #define KSZ9477_SPI_TURNAROUND_SHIFT 5 |
30 | |
31 | KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT, |
32 | KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN); |
33 | |
34 | KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT, |
35 | KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN); |
36 | |
37 | KSZ_REGMAP_TABLE(ksz9477, 32, KSZ9477_SPI_ADDR_SHIFT, |
38 | KSZ9477_SPI_TURNAROUND_SHIFT, KSZ9477_SPI_ADDR_ALIGN); |
39 | |
40 | static int ksz_spi_probe(struct spi_device *spi) |
41 | { |
42 | const struct regmap_config *regmap_config; |
43 | const struct ksz_chip_data *chip; |
44 | struct device *ddev = &spi->dev; |
45 | struct regmap_config rc; |
46 | struct ksz_device *dev; |
47 | int i, ret = 0; |
48 | |
49 | dev = ksz_switch_alloc(base: &spi->dev, priv: spi); |
50 | if (!dev) |
51 | return -ENOMEM; |
52 | |
53 | chip = device_get_match_data(dev: ddev); |
54 | if (!chip) |
55 | return -EINVAL; |
56 | |
57 | if (chip->chip_id == KSZ8830_CHIP_ID) |
58 | regmap_config = ksz8863_regmap_config; |
59 | else if (chip->chip_id == KSZ8795_CHIP_ID || |
60 | chip->chip_id == KSZ8794_CHIP_ID || |
61 | chip->chip_id == KSZ8765_CHIP_ID) |
62 | regmap_config = ksz8795_regmap_config; |
63 | else |
64 | regmap_config = ksz9477_regmap_config; |
65 | |
66 | for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { |
67 | rc = regmap_config[i]; |
68 | rc.lock_arg = &dev->regmap_mutex; |
69 | rc.wr_table = chip->wr_table; |
70 | rc.rd_table = chip->rd_table; |
71 | dev->regmap[i] = devm_regmap_init_spi(spi, &rc); |
72 | |
73 | if (IS_ERR(ptr: dev->regmap[i])) { |
74 | return dev_err_probe(dev: &spi->dev, err: PTR_ERR(ptr: dev->regmap[i]), |
75 | fmt: "Failed to initialize regmap%i\n" , |
76 | regmap_config[i].val_bits); |
77 | } |
78 | } |
79 | |
80 | if (spi->dev.platform_data) |
81 | dev->pdata = spi->dev.platform_data; |
82 | |
83 | /* setup spi */ |
84 | spi->mode = SPI_MODE_3; |
85 | ret = spi_setup(spi); |
86 | if (ret) |
87 | return ret; |
88 | |
89 | dev->irq = spi->irq; |
90 | |
91 | ret = ksz_switch_register(dev); |
92 | |
93 | /* Main DSA driver may not be started yet. */ |
94 | if (ret) |
95 | return ret; |
96 | |
97 | spi_set_drvdata(spi, data: dev); |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | static void ksz_spi_remove(struct spi_device *spi) |
103 | { |
104 | struct ksz_device *dev = spi_get_drvdata(spi); |
105 | |
106 | if (dev) |
107 | ksz_switch_remove(dev); |
108 | } |
109 | |
110 | static void ksz_spi_shutdown(struct spi_device *spi) |
111 | { |
112 | struct ksz_device *dev = spi_get_drvdata(spi); |
113 | |
114 | if (!dev) |
115 | return; |
116 | |
117 | ksz_switch_shutdown(dev); |
118 | |
119 | spi_set_drvdata(spi, NULL); |
120 | } |
121 | |
122 | static const struct of_device_id ksz_dt_ids[] = { |
123 | { |
124 | .compatible = "microchip,ksz8765" , |
125 | .data = &ksz_switch_chips[KSZ8765] |
126 | }, |
127 | { |
128 | .compatible = "microchip,ksz8794" , |
129 | .data = &ksz_switch_chips[KSZ8794] |
130 | }, |
131 | { |
132 | .compatible = "microchip,ksz8795" , |
133 | .data = &ksz_switch_chips[KSZ8795] |
134 | }, |
135 | { |
136 | .compatible = "microchip,ksz8863" , |
137 | .data = &ksz_switch_chips[KSZ8830] |
138 | }, |
139 | { |
140 | .compatible = "microchip,ksz8873" , |
141 | .data = &ksz_switch_chips[KSZ8830] |
142 | }, |
143 | { |
144 | .compatible = "microchip,ksz9477" , |
145 | .data = &ksz_switch_chips[KSZ9477] |
146 | }, |
147 | { |
148 | .compatible = "microchip,ksz9896" , |
149 | .data = &ksz_switch_chips[KSZ9896] |
150 | }, |
151 | { |
152 | .compatible = "microchip,ksz9897" , |
153 | .data = &ksz_switch_chips[KSZ9897] |
154 | }, |
155 | { |
156 | .compatible = "microchip,ksz9893" , |
157 | .data = &ksz_switch_chips[KSZ9893] |
158 | }, |
159 | { |
160 | .compatible = "microchip,ksz9563" , |
161 | .data = &ksz_switch_chips[KSZ9563] |
162 | }, |
163 | { |
164 | .compatible = "microchip,ksz8563" , |
165 | .data = &ksz_switch_chips[KSZ8563] |
166 | }, |
167 | { |
168 | .compatible = "microchip,ksz8567" , |
169 | .data = &ksz_switch_chips[KSZ8567] |
170 | }, |
171 | { |
172 | .compatible = "microchip,ksz9567" , |
173 | .data = &ksz_switch_chips[KSZ9567] |
174 | }, |
175 | { |
176 | .compatible = "microchip,lan9370" , |
177 | .data = &ksz_switch_chips[LAN9370] |
178 | }, |
179 | { |
180 | .compatible = "microchip,lan9371" , |
181 | .data = &ksz_switch_chips[LAN9371] |
182 | }, |
183 | { |
184 | .compatible = "microchip,lan9372" , |
185 | .data = &ksz_switch_chips[LAN9372] |
186 | }, |
187 | { |
188 | .compatible = "microchip,lan9373" , |
189 | .data = &ksz_switch_chips[LAN9373] |
190 | }, |
191 | { |
192 | .compatible = "microchip,lan9374" , |
193 | .data = &ksz_switch_chips[LAN9374] |
194 | }, |
195 | {}, |
196 | }; |
197 | MODULE_DEVICE_TABLE(of, ksz_dt_ids); |
198 | |
199 | static const struct spi_device_id ksz_spi_ids[] = { |
200 | { "ksz8765" }, |
201 | { "ksz8794" }, |
202 | { "ksz8795" }, |
203 | { "ksz8863" }, |
204 | { "ksz8873" }, |
205 | { "ksz9477" }, |
206 | { "ksz9896" }, |
207 | { "ksz9897" }, |
208 | { "ksz9893" }, |
209 | { "ksz9563" }, |
210 | { "ksz8563" }, |
211 | { "ksz8567" }, |
212 | { "ksz9567" }, |
213 | { "lan9370" }, |
214 | { "lan9371" }, |
215 | { "lan9372" }, |
216 | { "lan9373" }, |
217 | { "lan9374" }, |
218 | { }, |
219 | }; |
220 | MODULE_DEVICE_TABLE(spi, ksz_spi_ids); |
221 | |
222 | static struct spi_driver ksz_spi_driver = { |
223 | .driver = { |
224 | .name = "ksz-switch" , |
225 | .owner = THIS_MODULE, |
226 | .of_match_table = ksz_dt_ids, |
227 | }, |
228 | .id_table = ksz_spi_ids, |
229 | .probe = ksz_spi_probe, |
230 | .remove = ksz_spi_remove, |
231 | .shutdown = ksz_spi_shutdown, |
232 | }; |
233 | |
234 | module_spi_driver(ksz_spi_driver); |
235 | |
236 | MODULE_ALIAS("spi:ksz9477" ); |
237 | MODULE_ALIAS("spi:ksz9896" ); |
238 | MODULE_ALIAS("spi:ksz9897" ); |
239 | MODULE_ALIAS("spi:ksz9893" ); |
240 | MODULE_ALIAS("spi:ksz9563" ); |
241 | MODULE_ALIAS("spi:ksz8563" ); |
242 | MODULE_ALIAS("spi:ksz9567" ); |
243 | MODULE_ALIAS("spi:lan937x" ); |
244 | MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>" ); |
245 | MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver" ); |
246 | MODULE_LICENSE("GPL" ); |
247 | |