File Index
Files and directories
Sign in
FILE

lan9252.c

File preview with syntax highlighting.

linux-6.19.14/drivers/misc/keba/lan9252.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) KEBA Industrial Automation Gmbh 2024
  4 *
  5 * Driver for LAN9252 on KEBA CP500 devices
  6 *
  7 * This driver is used for updating the configuration of the LAN9252 controller
  8 * on KEBA CP500 devices. The LAN9252 is connected over SPI, which is also named
  9 * PDI.
 10 */
 11
 12#include <linux/spi/spi.h>
 13#include <linux/mii.h>
 14
 15/* SPI commands */
 16#define LAN9252_SPI_READ	0x3
 17#define LAN9252_SPI_WRITE	0x2
 18
 19struct lan9252_read_cmd {
 20	u8 cmd;
 21	u8 addr_0;
 22	u8 addr_1;
 23} __packed;
 24
 25struct lan9252_write_cmd {
 26	u8 cmd;
 27	u8 addr_0;
 28	u8 addr_1;
 29	u32 data;
 30} __packed;
 31
 32/* byte test register */
 33#define LAN9252_BYTE_TEST		0x64
 34#define   LAN9252_BYTE_TEST_VALUE	0x87654321
 35
 36/* hardware configuration register */
 37#define LAN9252_HW_CFG		0x74
 38#define   LAN9252_HW_CFG_READY	0x08000000
 39
 40/* EtherCAT CSR interface data register */
 41#define LAN9252_ECAT_CSR_DATA	0x300
 42
 43/* EtherCAT CSR interface command register */
 44#define LAN9252_ECAT_CSR_CMD	0x304
 45#define   LAN9252_ECAT_CSR_BUSY	0x80000000
 46#define   LAN9252_ECAT_CSR_READ	0x40000000
 47
 48/* EtherCAT slave controller MII register */
 49#define LAN9252_ESC_MII			0x510
 50#define   LAN9252_ESC_MII_BUSY		0x8000
 51#define   LAN9252_ESC_MII_CMD_ERR	0x4000
 52#define   LAN9252_ESC_MII_READ_ERR	0x2000
 53#define   LAN9252_ESC_MII_ERR_MASK	(LAN9252_ESC_MII_CMD_ERR | \
 54					 LAN9252_ESC_MII_READ_ERR)
 55#define   LAN9252_ESC_MII_WRITE		0x0200
 56#define   LAN9252_ESC_MII_READ		0x0100
 57
 58/* EtherCAT slave controller PHY address register */
 59#define LAN9252_ESC_PHY_ADDR		0x512
 60
 61/* EtherCAT slave controller PHY register address register */
 62#define LAN9252_ESC_PHY_REG_ADDR	0x513
 63
 64/* EtherCAT slave controller PHY data register */
 65#define LAN9252_ESC_PHY_DATA		0x514
 66
 67/* EtherCAT slave controller PDI access state register */
 68#define LAN9252_ESC_MII_PDI		0x517
 69#define   LAN9252_ESC_MII_ACCESS_PDI	0x01
 70#define   LAN9252_ESC_MII_ACCESS_ECAT	0x00
 71
 72/* PHY address */
 73#define PHY_ADDRESS	2
 74
 75#define SPI_RETRY_COUNT		10
 76#define SPI_WAIT_US		100
 77#define SPI_CSR_WAIT_US		500
 78
 79static int lan9252_spi_read(struct spi_device *spi, u16 addr, u32 *data)
 80{
 81	struct lan9252_read_cmd cmd;
 82
 83	cmd.cmd = LAN9252_SPI_READ;
 84	cmd.addr_0 = (addr >> 8) & 0xFF;
 85	cmd.addr_1 = addr & 0xFF;
 86
 87	return spi_write_then_read(spi, (u8 *)&cmd,
 88				   sizeof(struct lan9252_read_cmd),
 89				   (u8 *)data, sizeof(u32));
 90}
 91
 92static int lan9252_spi_write(struct spi_device *spi, u16 addr, u32 data)
 93{
 94	struct lan9252_write_cmd cmd;
 95
 96	cmd.cmd = LAN9252_SPI_WRITE;
 97	cmd.addr_0 = (addr >> 8) & 0xFF;
 98	cmd.addr_1 = addr & 0xFF;
 99	cmd.data = data;
100
101	return spi_write(spi, (u8 *)&cmd, sizeof(struct lan9252_write_cmd));
102}
103
104static bool lan9252_init(struct spi_device *spi)
105{
106	u32 data;
107	int ret;
108
109	ret = lan9252_spi_read(spi, LAN9252_BYTE_TEST, &data);
110	if (ret || data != LAN9252_BYTE_TEST_VALUE)
111		return false;
112
113	ret = lan9252_spi_read(spi, LAN9252_HW_CFG, &data);
114	if (ret || !(data & LAN9252_HW_CFG_READY))
115		return false;
116
117	return true;
118}
119
120static u8 lan9252_esc_get_size(u16 addr)
121{
122	if (addr == LAN9252_ESC_MII || addr == LAN9252_ESC_PHY_DATA)
123		return 2;
124
125	return 1;
126}
127
128static int lan9252_esc_wait(struct spi_device *spi)
129{
130	ktime_t timeout = ktime_add_us(ktime_get(), SPI_WAIT_US);
131	u32 data;
132	int ret;
133
134	/* wait while CSR command is busy */
135	for (;;) {
136		ret = lan9252_spi_read(spi, LAN9252_ECAT_CSR_CMD, &data);
137		if (ret)
138			return ret;
139		if (!(data & LAN9252_ECAT_CSR_BUSY))
140			return 0;
141
142		if (ktime_compare(ktime_get(), timeout) > 0) {
143			ret = lan9252_spi_read(spi, LAN9252_ECAT_CSR_CMD, &data);
144			if (ret)
145				return ret;
146			break;
147		}
148	}
149
150	return (!(data & LAN9252_ECAT_CSR_BUSY)) ? 0 : -ETIMEDOUT;
151}
152
153static int lan9252_esc_read(struct spi_device *spi, u16 addr, u32 *data)
154{
155	u32 csr_cmd;
156	u8 size;
157	int ret;
158
159	size = lan9252_esc_get_size(addr);
160	csr_cmd = LAN9252_ECAT_CSR_BUSY | LAN9252_ECAT_CSR_READ;
161	csr_cmd |= (size << 16) | addr;
162	ret = lan9252_spi_write(spi, LAN9252_ECAT_CSR_CMD, csr_cmd);
163	if (ret)
164		return ret;
165
166	ret = lan9252_esc_wait(spi);
167	if (ret)
168		return ret;
169
170	ret = lan9252_spi_read(spi, LAN9252_ECAT_CSR_DATA, data);
171	if (ret)
172		return ret;
173
174	return 0;
175}
176
177static int lan9252_esc_write(struct spi_device *spi, u16 addr, u32 data)
178{
179	u32 csr_cmd;
180	u8 size;
181	int ret;
182
183	ret = lan9252_spi_write(spi, LAN9252_ECAT_CSR_DATA, data);
184	if (ret)
185		return ret;
186
187	size = lan9252_esc_get_size(addr);
188	csr_cmd = LAN9252_ECAT_CSR_BUSY;
189	csr_cmd |= (size << 16) | addr;
190	ret = lan9252_spi_write(spi, LAN9252_ECAT_CSR_CMD, csr_cmd);
191	if (ret)
192		return ret;
193
194	ret = lan9252_esc_wait(spi);
195	if (ret)
196		return ret;
197
198	return 0;
199}
200
201static int lan9252_access_mii(struct spi_device *spi, bool access)
202{
203	u32 data;
204
205	if (access)
206		data = LAN9252_ESC_MII_ACCESS_PDI;
207	else
208		data = LAN9252_ESC_MII_ACCESS_ECAT;
209
210	return lan9252_esc_write(spi, LAN9252_ESC_MII_PDI, data);
211}
212
213static int lan9252_mii_wait(struct spi_device *spi)
214{
215	ktime_t timeout = ktime_add_us(ktime_get(), SPI_CSR_WAIT_US);
216	u32 data;
217	int ret;
218
219	/* wait while MII control state machine is busy */
220	for (;;) {
221		ret = lan9252_esc_read(spi, LAN9252_ESC_MII, &data);
222		if (ret)
223			return ret;
224		if (data & LAN9252_ESC_MII_ERR_MASK)
225			return -EIO;
226		if (!(data & LAN9252_ESC_MII_BUSY))
227			return 0;
228
229		if (ktime_compare(ktime_get(), timeout) > 0) {
230			ret = lan9252_esc_read(spi, LAN9252_ESC_MII, &data);
231			if (ret)
232				return ret;
233			if (data & LAN9252_ESC_MII_ERR_MASK)
234				return -EIO;
235			break;
236		}
237	}
238
239	return (!(data & LAN9252_ESC_MII_BUSY)) ? 0 : -ETIMEDOUT;
240}
241
242static int lan9252_mii_read(struct spi_device *spi, u8 phy_addr, u8 reg_addr,
243			    u32 *data)
244{
245	int ret;
246
247	ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_ADDR, phy_addr);
248	if (ret)
249		return ret;
250	ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_REG_ADDR, reg_addr);
251	if (ret)
252		return ret;
253
254	ret = lan9252_esc_write(spi, LAN9252_ESC_MII, LAN9252_ESC_MII_READ);
255	if (ret)
256		return ret;
257
258	ret = lan9252_mii_wait(spi);
259	if (ret)
260		return ret;
261
262	return lan9252_esc_read(spi, LAN9252_ESC_PHY_DATA, data);
263}
264
265static int lan9252_mii_write(struct spi_device *spi, u8 phy_addr, u8 reg_addr,
266			     u32 data)
267{
268	int ret;
269
270	ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_ADDR, phy_addr);
271	if (ret)
272		return ret;
273	ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_REG_ADDR, reg_addr);
274	if (ret)
275		return ret;
276	ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_DATA, data);
277	if (ret)
278		return ret;
279
280	ret = lan9252_esc_write(spi, LAN9252_ESC_MII, LAN9252_ESC_MII_WRITE);
281	if (ret)
282		return ret;
283
284	return lan9252_mii_wait(spi);
285}
286
287static int lan9252_probe(struct spi_device *spi)
288{
289	u32 data;
290	int retry = SPI_RETRY_COUNT;
291	int ret;
292
293	/* execute specified initialization sequence */
294	while (retry && !lan9252_init(spi))
295		retry--;
296	if (retry == 0) {
297		dev_err(&spi->dev,
298			"Can't initialize LAN9252 SPI communication!");
299		return -EIO;
300	}
301
302	/* enable access to MII management for PDI */
303	ret = lan9252_access_mii(spi, true);
304	if (ret) {
305		dev_err(&spi->dev, "Can't enable access to MII management!");
306		return ret;
307	}
308
309	/*
310	 * check PHY configuration and configure if necessary
311	 *	- full duplex
312	 *	- auto negotiation disabled
313	 *	- 100 Mbps
314	 */
315	ret = lan9252_mii_read(spi, PHY_ADDRESS, MII_BMCR, &data);
316	if (ret) {
317		dev_err(&spi->dev, "Can't read LAN9252 configuration!");
318		goto out;
319	}
320	if (!(data & BMCR_FULLDPLX) || (data & BMCR_ANENABLE) ||
321	    !(data & BMCR_SPEED100)) {
322		/*
323		 */
324		data &= ~(BMCR_ANENABLE);
325		data |= (BMCR_FULLDPLX | BMCR_SPEED100);
326		ret = lan9252_mii_write(spi, PHY_ADDRESS, MII_BMCR, data);
327		if (ret)
328			dev_err(&spi->dev,
329				"Can't write LAN9252 configuration!");
330	}
331
332	dev_info(&spi->dev, "LAN9252 PHY configuration");
333
334out:
335	/* disable access to MII management for PDI */
336	lan9252_access_mii(spi, false);
337
338	return ret;
339}
340
341static const struct spi_device_id lan9252_id[] = {
342	{"lan9252"},
343	{}
344};
345MODULE_DEVICE_TABLE(spi, lan9252_id);
346
347static struct spi_driver lan9252_driver = {
348	.driver = {
349		.name	= "lan9252",
350	},
351	.probe		= lan9252_probe,
352	.id_table	= lan9252_id,
353};
354module_spi_driver(lan9252_driver);
355
356MODULE_AUTHOR("Petar Bojanic <boja@keba.com>");
357MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>");
358MODULE_DESCRIPTION("KEBA LAN9252 driver");
359MODULE_LICENSE("GPL");
~/ Read-only file preview.