File Index
Files and directories
Sign in
FILE

ksz_spi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/dsa/microchip/ksz_spi.c C
  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 KSZ8463_SPI_ADDR_SHIFT			13
 20#define KSZ8463_SPI_ADDR_ALIGN			3
 21#define KSZ8463_SPI_TURNAROUND_SHIFT		2
 22
 23#define KSZ8795_SPI_ADDR_SHIFT			12
 24#define KSZ8795_SPI_ADDR_ALIGN			3
 25#define KSZ8795_SPI_TURNAROUND_SHIFT		1
 26
 27#define KSZ8863_SPI_ADDR_SHIFT			8
 28#define KSZ8863_SPI_ADDR_ALIGN			8
 29#define KSZ8863_SPI_TURNAROUND_SHIFT		0
 30
 31#define KSZ9477_SPI_ADDR_SHIFT			24
 32#define KSZ9477_SPI_ADDR_ALIGN			3
 33#define KSZ9477_SPI_TURNAROUND_SHIFT		5
 34
 35KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT,
 36		 KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN);
 37
 38KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
 39		 KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN);
 40
 41KSZ_REGMAP_TABLE(ksz9477, 32, KSZ9477_SPI_ADDR_SHIFT,
 42		 KSZ9477_SPI_TURNAROUND_SHIFT, KSZ9477_SPI_ADDR_ALIGN);
 43
 44static u16 ksz8463_reg(u16 reg, size_t size)
 45{
 46	switch (size) {
 47	case 1:
 48		reg = ((reg >> 2) << 4) | (1 << (reg & 3));
 49		break;
 50	case 2:
 51		reg = ((reg >> 2) << 4) | (reg & 2 ? 0x0c : 0x03);
 52		break;
 53	default:
 54		reg = ((reg >> 2) << 4) | 0xf;
 55		break;
 56	}
 57	reg <<= KSZ8463_SPI_TURNAROUND_SHIFT;
 58	return reg;
 59}
 60
 61static int ksz8463_spi_read(void *context,
 62			    const void *reg, size_t reg_size,
 63			    void *val, size_t val_size)
 64{
 65	struct device *dev = context;
 66	struct spi_device *spi = to_spi_device(dev);
 67	u8 bytes[2];
 68	u16 cmd;
 69	int rc;
 70
 71	if (reg_size > 2 || val_size > 4)
 72		return -EINVAL;
 73	memcpy(&cmd, reg, sizeof(u16));
 74	cmd = ksz8463_reg(cmd, val_size);
 75	/* SPI command uses big-endian format. */
 76	put_unaligned_be16(cmd, bytes);
 77	rc = spi_write_then_read(spi, bytes, reg_size, val, val_size);
 78#if defined(__BIG_ENDIAN)
 79	/* Register value uses little-endian format so need to convert when
 80	 * running in big-endian system.
 81	 */
 82	if (!rc && val_size > 1) {
 83		if (val_size == 2) {
 84			u16 v = get_unaligned_le16(val);
 85
 86			memcpy(val, &v, sizeof(v));
 87		} else if (val_size == 4) {
 88			u32 v = get_unaligned_le32(val);
 89
 90			memcpy(val, &v, sizeof(v));
 91		}
 92	}
 93#endif
 94	return rc;
 95}
 96
 97static int ksz8463_spi_write(void *context, const void *data, size_t count)
 98{
 99	struct device *dev = context;
100	struct spi_device *spi = to_spi_device(dev);
101	size_t val_size = count - 2;
102	u8 bytes[6];
103	u16 cmd;
104
105	if (count <= 2 || count > 6)
106		return -EINVAL;
107	memcpy(bytes, data, count);
108	memcpy(&cmd, data, sizeof(u16));
109	cmd = ksz8463_reg(cmd, val_size);
110	cmd |= (1 << (KSZ8463_SPI_ADDR_SHIFT + KSZ8463_SPI_TURNAROUND_SHIFT));
111	/* SPI command uses big-endian format. */
112	put_unaligned_be16(cmd, bytes);
113#if defined(__BIG_ENDIAN)
114	/* Register value uses little-endian format so need to convert when
115	 * running in big-endian system.
116	 */
117	if (val_size == 2) {
118		u8 *val = &bytes[2];
119		u16 v;
120
121		memcpy(&v, val, sizeof(v));
122		put_unaligned_le16(v, val);
123	} else if (val_size == 4) {
124		u8 *val = &bytes[2];
125		u32 v;
126
127		memcpy(&v, val, sizeof(v));
128		put_unaligned_le32(v, val);
129	}
130#endif
131	return spi_write(spi, bytes, count);
132}
133
134KSZ8463_REGMAP_TABLE(ksz8463, KSZ8463_SPI_ADDR_SHIFT, 0,
135		     KSZ8463_SPI_ADDR_ALIGN);
136
137static int ksz_spi_probe(struct spi_device *spi)
138{
139	const struct regmap_config *regmap_config;
140	const struct ksz_chip_data *chip;
141	struct device *ddev = &spi->dev;
142	struct regmap_config rc;
143	struct ksz_device *dev;
144	int i, ret = 0;
145
146	dev = ksz_switch_alloc(&spi->dev, spi);
147	if (!dev)
148		return -ENOMEM;
149
150	chip = device_get_match_data(ddev);
151	if (!chip)
152		return -EINVAL;
153
154	/* Save chip id to do special initialization when probing. */
155	dev->chip_id = chip->chip_id;
156	if (chip->chip_id == KSZ88X3_CHIP_ID)
157		regmap_config = ksz8863_regmap_config;
158	else if (chip->chip_id == KSZ8463_CHIP_ID)
159		regmap_config = ksz8463_regmap_config;
160	else if (chip->chip_id == KSZ8795_CHIP_ID ||
161		 chip->chip_id == KSZ8794_CHIP_ID ||
162		 chip->chip_id == KSZ8765_CHIP_ID)
163		regmap_config = ksz8795_regmap_config;
164	else if (chip->chip_id == KSZ8895_CHIP_ID ||
165		 chip->chip_id == KSZ8864_CHIP_ID)
166		regmap_config = ksz8863_regmap_config;
167	else
168		regmap_config = ksz9477_regmap_config;
169
170	for (i = 0; i < __KSZ_NUM_REGMAPS; i++) {
171		rc = regmap_config[i];
172		rc.lock_arg = &dev->regmap_mutex;
173		rc.wr_table = chip->wr_table;
174		rc.rd_table = chip->rd_table;
175		dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
176
177		if (IS_ERR(dev->regmap[i])) {
178			return dev_err_probe(&spi->dev, PTR_ERR(dev->regmap[i]),
179					     "Failed to initialize regmap%i\n",
180					     regmap_config[i].val_bits);
181		}
182	}
183
184	if (spi->dev.platform_data)
185		dev->pdata = spi->dev.platform_data;
186
187	/* setup spi */
188	spi->mode = SPI_MODE_3;
189	ret = spi_setup(spi);
190	if (ret)
191		return ret;
192
193	dev->irq = spi->irq;
194
195	ret = ksz_switch_register(dev);
196
197	/* Main DSA driver may not be started yet. */
198	if (ret)
199		return ret;
200
201	spi_set_drvdata(spi, dev);
202
203	return 0;
204}
205
206static void ksz_spi_remove(struct spi_device *spi)
207{
208	struct ksz_device *dev = spi_get_drvdata(spi);
209
210	if (dev)
211		ksz_switch_remove(dev);
212}
213
214static void ksz_spi_shutdown(struct spi_device *spi)
215{
216	struct ksz_device *dev = spi_get_drvdata(spi);
217
218	if (!dev)
219		return;
220
221	ksz_switch_shutdown(dev);
222
223	spi_set_drvdata(spi, NULL);
224}
225
226static const struct of_device_id ksz_dt_ids[] = {
227	{
228		.compatible = "microchip,ksz8463",
229		.data = &ksz_switch_chips[KSZ8463]
230	},
231	{
232		.compatible = "microchip,ksz8765",
233		.data = &ksz_switch_chips[KSZ8765]
234	},
235	{
236		.compatible = "microchip,ksz8794",
237		.data = &ksz_switch_chips[KSZ8794]
238	},
239	{
240		.compatible = "microchip,ksz8795",
241		.data = &ksz_switch_chips[KSZ8795]
242	},
243	{
244		.compatible = "microchip,ksz8863",
245		.data = &ksz_switch_chips[KSZ88X3]
246	},
247	{
248		.compatible = "microchip,ksz8864",
249		.data = &ksz_switch_chips[KSZ8864]
250	},
251	{
252		.compatible = "microchip,ksz8873",
253		.data = &ksz_switch_chips[KSZ88X3]
254	},
255	{
256		.compatible = "microchip,ksz8895",
257		.data = &ksz_switch_chips[KSZ8895]
258	},
259	{
260		.compatible = "microchip,ksz9477",
261		.data = &ksz_switch_chips[KSZ9477]
262	},
263	{
264		.compatible = "microchip,ksz9896",
265		.data = &ksz_switch_chips[KSZ9896]
266	},
267	{
268		.compatible = "microchip,ksz9897",
269		.data = &ksz_switch_chips[KSZ9897]
270	},
271	{
272		.compatible = "microchip,ksz9893",
273		.data = &ksz_switch_chips[KSZ9893]
274	},
275	{
276		.compatible = "microchip,ksz9563",
277		.data = &ksz_switch_chips[KSZ9563]
278	},
279	{
280		.compatible = "microchip,ksz8563",
281		.data = &ksz_switch_chips[KSZ8563]
282	},
283	{
284		.compatible = "microchip,ksz8567",
285		.data = &ksz_switch_chips[KSZ8567]
286	},
287	{
288		.compatible = "microchip,ksz9567",
289		.data = &ksz_switch_chips[KSZ9567]
290	},
291	{
292		.compatible = "microchip,lan9370",
293		.data = &ksz_switch_chips[LAN9370]
294	},
295	{
296		.compatible = "microchip,lan9371",
297		.data = &ksz_switch_chips[LAN9371]
298	},
299	{
300		.compatible = "microchip,lan9372",
301		.data = &ksz_switch_chips[LAN9372]
302	},
303	{
304		.compatible = "microchip,lan9373",
305		.data = &ksz_switch_chips[LAN9373]
306	},
307	{
308		.compatible = "microchip,lan9374",
309		.data = &ksz_switch_chips[LAN9374]
310	},
311	{
312		.compatible = "microchip,lan9646",
313		.data = &ksz_switch_chips[LAN9646]
314	},
315	{},
316};
317MODULE_DEVICE_TABLE(of, ksz_dt_ids);
318
319static const struct spi_device_id ksz_spi_ids[] = {
320	{ "ksz8463" },
321	{ "ksz8765" },
322	{ "ksz8794" },
323	{ "ksz8795" },
324	{ "ksz8863" },
325	{ "ksz8864" },
326	{ "ksz8873" },
327	{ "ksz8895" },
328	{ "ksz9477" },
329	{ "ksz9896" },
330	{ "ksz9897" },
331	{ "ksz9893" },
332	{ "ksz9563" },
333	{ "ksz8563" },
334	{ "ksz8567" },
335	{ "ksz9567" },
336	{ "lan9370" },
337	{ "lan9371" },
338	{ "lan9372" },
339	{ "lan9373" },
340	{ "lan9374" },
341	{ "lan9646" },
342	{ },
343};
344MODULE_DEVICE_TABLE(spi, ksz_spi_ids);
345
346static DEFINE_SIMPLE_DEV_PM_OPS(ksz_spi_pm_ops,
347				ksz_switch_suspend, ksz_switch_resume);
348
349static struct spi_driver ksz_spi_driver = {
350	.driver = {
351		.name	= "ksz-switch",
352		.of_match_table = ksz_dt_ids,
353		.pm = &ksz_spi_pm_ops,
354	},
355	.id_table = ksz_spi_ids,
356	.probe	= ksz_spi_probe,
357	.remove	= ksz_spi_remove,
358	.shutdown = ksz_spi_shutdown,
359};
360
361module_spi_driver(ksz_spi_driver);
362
363MODULE_ALIAS("spi:lan937x");
364MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
365MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver");
366MODULE_LICENSE("GPL");
~/ Read-only file preview.