1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Microchip ksz series register access through SPI |
4 | * |
5 | * Copyright (C) 2017-2024 Microchip Technology Inc. |
6 | * Tristram Ha <Tristram.Ha@microchip.com> |
7 | */ |
8 | |
9 | #include <linux/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 | /* Save chip id to do special initialization when probing. */ |
58 | dev->chip_id = chip->chip_id; |
59 | if (chip->chip_id == KSZ88X3_CHIP_ID) |
60 | regmap_config = ksz8863_regmap_config; |
61 | else if (chip->chip_id == KSZ8795_CHIP_ID || |
62 | chip->chip_id == KSZ8794_CHIP_ID || |
63 | chip->chip_id == KSZ8765_CHIP_ID) |
64 | regmap_config = ksz8795_regmap_config; |
65 | else if (chip->chip_id == KSZ8895_CHIP_ID || |
66 | chip->chip_id == KSZ8864_CHIP_ID) |
67 | regmap_config = ksz8863_regmap_config; |
68 | else |
69 | regmap_config = ksz9477_regmap_config; |
70 | |
71 | for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { |
72 | rc = regmap_config[i]; |
73 | rc.lock_arg = &dev->regmap_mutex; |
74 | rc.wr_table = chip->wr_table; |
75 | rc.rd_table = chip->rd_table; |
76 | dev->regmap[i] = devm_regmap_init_spi(spi, &rc); |
77 | |
78 | if (IS_ERR(ptr: dev->regmap[i])) { |
79 | return dev_err_probe(dev: &spi->dev, err: PTR_ERR(ptr: dev->regmap[i]), |
80 | fmt: "Failed to initialize regmap%i\n" , |
81 | regmap_config[i].val_bits); |
82 | } |
83 | } |
84 | |
85 | if (spi->dev.platform_data) |
86 | dev->pdata = spi->dev.platform_data; |
87 | |
88 | /* setup spi */ |
89 | spi->mode = SPI_MODE_3; |
90 | ret = spi_setup(spi); |
91 | if (ret) |
92 | return ret; |
93 | |
94 | dev->irq = spi->irq; |
95 | |
96 | ret = ksz_switch_register(dev); |
97 | |
98 | /* Main DSA driver may not be started yet. */ |
99 | if (ret) |
100 | return ret; |
101 | |
102 | spi_set_drvdata(spi, data: dev); |
103 | |
104 | return 0; |
105 | } |
106 | |
107 | static void ksz_spi_remove(struct spi_device *spi) |
108 | { |
109 | struct ksz_device *dev = spi_get_drvdata(spi); |
110 | |
111 | if (dev) |
112 | ksz_switch_remove(dev); |
113 | } |
114 | |
115 | static void ksz_spi_shutdown(struct spi_device *spi) |
116 | { |
117 | struct ksz_device *dev = spi_get_drvdata(spi); |
118 | |
119 | if (!dev) |
120 | return; |
121 | |
122 | ksz_switch_shutdown(dev); |
123 | |
124 | spi_set_drvdata(spi, NULL); |
125 | } |
126 | |
127 | static const struct of_device_id ksz_dt_ids[] = { |
128 | { |
129 | .compatible = "microchip,ksz8765" , |
130 | .data = &ksz_switch_chips[KSZ8765] |
131 | }, |
132 | { |
133 | .compatible = "microchip,ksz8794" , |
134 | .data = &ksz_switch_chips[KSZ8794] |
135 | }, |
136 | { |
137 | .compatible = "microchip,ksz8795" , |
138 | .data = &ksz_switch_chips[KSZ8795] |
139 | }, |
140 | { |
141 | .compatible = "microchip,ksz8863" , |
142 | .data = &ksz_switch_chips[KSZ88X3] |
143 | }, |
144 | { |
145 | .compatible = "microchip,ksz8864" , |
146 | .data = &ksz_switch_chips[KSZ8864] |
147 | }, |
148 | { |
149 | .compatible = "microchip,ksz8873" , |
150 | .data = &ksz_switch_chips[KSZ88X3] |
151 | }, |
152 | { |
153 | .compatible = "microchip,ksz8895" , |
154 | .data = &ksz_switch_chips[KSZ8895] |
155 | }, |
156 | { |
157 | .compatible = "microchip,ksz9477" , |
158 | .data = &ksz_switch_chips[KSZ9477] |
159 | }, |
160 | { |
161 | .compatible = "microchip,ksz9896" , |
162 | .data = &ksz_switch_chips[KSZ9896] |
163 | }, |
164 | { |
165 | .compatible = "microchip,ksz9897" , |
166 | .data = &ksz_switch_chips[KSZ9897] |
167 | }, |
168 | { |
169 | .compatible = "microchip,ksz9893" , |
170 | .data = &ksz_switch_chips[KSZ9893] |
171 | }, |
172 | { |
173 | .compatible = "microchip,ksz9563" , |
174 | .data = &ksz_switch_chips[KSZ9563] |
175 | }, |
176 | { |
177 | .compatible = "microchip,ksz8563" , |
178 | .data = &ksz_switch_chips[KSZ8563] |
179 | }, |
180 | { |
181 | .compatible = "microchip,ksz8567" , |
182 | .data = &ksz_switch_chips[KSZ8567] |
183 | }, |
184 | { |
185 | .compatible = "microchip,ksz9567" , |
186 | .data = &ksz_switch_chips[KSZ9567] |
187 | }, |
188 | { |
189 | .compatible = "microchip,lan9370" , |
190 | .data = &ksz_switch_chips[LAN9370] |
191 | }, |
192 | { |
193 | .compatible = "microchip,lan9371" , |
194 | .data = &ksz_switch_chips[LAN9371] |
195 | }, |
196 | { |
197 | .compatible = "microchip,lan9372" , |
198 | .data = &ksz_switch_chips[LAN9372] |
199 | }, |
200 | { |
201 | .compatible = "microchip,lan9373" , |
202 | .data = &ksz_switch_chips[LAN9373] |
203 | }, |
204 | { |
205 | .compatible = "microchip,lan9374" , |
206 | .data = &ksz_switch_chips[LAN9374] |
207 | }, |
208 | { |
209 | .compatible = "microchip,lan9646" , |
210 | .data = &ksz_switch_chips[LAN9646] |
211 | }, |
212 | {}, |
213 | }; |
214 | MODULE_DEVICE_TABLE(of, ksz_dt_ids); |
215 | |
216 | static const struct spi_device_id ksz_spi_ids[] = { |
217 | { "ksz8765" }, |
218 | { "ksz8794" }, |
219 | { "ksz8795" }, |
220 | { "ksz8863" }, |
221 | { "ksz8864" }, |
222 | { "ksz8873" }, |
223 | { "ksz8895" }, |
224 | { "ksz9477" }, |
225 | { "ksz9896" }, |
226 | { "ksz9897" }, |
227 | { "ksz9893" }, |
228 | { "ksz9563" }, |
229 | { "ksz8563" }, |
230 | { "ksz8567" }, |
231 | { "ksz9567" }, |
232 | { "lan9370" }, |
233 | { "lan9371" }, |
234 | { "lan9372" }, |
235 | { "lan9373" }, |
236 | { "lan9374" }, |
237 | { "lan9646" }, |
238 | { }, |
239 | }; |
240 | MODULE_DEVICE_TABLE(spi, ksz_spi_ids); |
241 | |
242 | static DEFINE_SIMPLE_DEV_PM_OPS(ksz_spi_pm_ops, |
243 | ksz_switch_suspend, ksz_switch_resume); |
244 | |
245 | static struct spi_driver ksz_spi_driver = { |
246 | .driver = { |
247 | .name = "ksz-switch" , |
248 | .of_match_table = ksz_dt_ids, |
249 | .pm = &ksz_spi_pm_ops, |
250 | }, |
251 | .id_table = ksz_spi_ids, |
252 | .probe = ksz_spi_probe, |
253 | .remove = ksz_spi_remove, |
254 | .shutdown = ksz_spi_shutdown, |
255 | }; |
256 | |
257 | module_spi_driver(ksz_spi_driver); |
258 | |
259 | MODULE_ALIAS("spi:lan937x" ); |
260 | MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>" ); |
261 | MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver" ); |
262 | MODULE_LICENSE("GPL" ); |
263 | |