Merge tag 'hid-for-linus-2024031301' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / drivers / net / ethernet / qualcomm / qca_7k.c
CommitLineData
060e309a 1// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
291ab06e 2/*
291ab06e
SW
3 * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
4 * Copyright (c) 2014, I2SE GmbH
291ab06e
SW
5 */
6
7/* This module implements the Qualcomm Atheros SPI protocol for
8 * kernel-based SPI device.
9 */
10
ce68349a
SW
11#include <linux/kernel.h>
12#include <linux/netdevice.h>
291ab06e 13#include <linux/spi/spi.h>
291ab06e
SW
14
15#include "qca_7k.h"
16
17void
18qcaspi_spi_error(struct qcaspi *qca)
19{
20 if (qca->sync != QCASPI_SYNC_READY)
21 return;
22
23 netdev_err(qca->net_dev, "spi error\n");
24 qca->sync = QCASPI_SYNC_UNKNOWN;
25 qca->stats.spi_err++;
26}
27
28int
29qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result)
30{
31 __be16 rx_data;
32 __be16 tx_data;
e65a9e48
SW
33 struct spi_transfer transfer[2];
34 struct spi_message msg;
291ab06e
SW
35 int ret;
36
e65a9e48
SW
37 memset(transfer, 0, sizeof(transfer));
38
39 spi_message_init(&msg);
40
291ab06e 41 tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg);
e65a9e48
SW
42 *result = 0;
43
44 transfer[0].tx_buf = &tx_data;
45 transfer[0].len = QCASPI_CMD_LEN;
46 transfer[1].rx_buf = &rx_data;
47 transfer[1].len = QCASPI_CMD_LEN;
48
49 spi_message_add_tail(&transfer[0], &msg);
291ab06e
SW
50
51 if (qca->legacy_mode) {
e65a9e48
SW
52 spi_sync(qca->spi_dev, &msg);
53 spi_message_init(&msg);
291ab06e 54 }
e65a9e48
SW
55 spi_message_add_tail(&transfer[1], &msg);
56 ret = spi_sync(qca->spi_dev, &msg);
291ab06e
SW
57
58 if (!ret)
e65a9e48 59 ret = msg.status;
291ab06e
SW
60
61 if (ret)
62 qcaspi_spi_error(qca);
63 else
64 *result = be16_to_cpu(rx_data);
65
66 return ret;
67}
68
48c1699e
SW
69static int
70__qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
291ab06e
SW
71{
72 __be16 tx_data[2];
e65a9e48
SW
73 struct spi_transfer transfer[2];
74 struct spi_message msg;
291ab06e
SW
75 int ret;
76
e65a9e48
SW
77 memset(&transfer, 0, sizeof(transfer));
78
79 spi_message_init(&msg);
80
291ab06e
SW
81 tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg);
82 tx_data[1] = cpu_to_be16(value);
83
e65a9e48
SW
84 transfer[0].tx_buf = &tx_data[0];
85 transfer[0].len = QCASPI_CMD_LEN;
86 transfer[1].tx_buf = &tx_data[1];
87 transfer[1].len = QCASPI_CMD_LEN;
88
89 spi_message_add_tail(&transfer[0], &msg);
291ab06e 90 if (qca->legacy_mode) {
e65a9e48
SW
91 spi_sync(qca->spi_dev, &msg);
92 spi_message_init(&msg);
291ab06e 93 }
e65a9e48
SW
94 spi_message_add_tail(&transfer[1], &msg);
95 ret = spi_sync(qca->spi_dev, &msg);
291ab06e
SW
96
97 if (!ret)
e65a9e48 98 ret = msg.status;
291ab06e
SW
99
100 if (ret)
101 qcaspi_spi_error(qca);
102
103 return ret;
104}
48c1699e
SW
105
106int
107qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry)
108{
109 int ret, i = 0;
110 u16 confirmed;
111
112 do {
113 ret = __qcaspi_write_register(qca, reg, value);
114 if (ret)
115 return ret;
116
117 if (!retry)
118 return 0;
119
120 ret = qcaspi_read_register(qca, reg, &confirmed);
121 if (ret)
122 return ret;
123
124 ret = confirmed != value;
125 if (!ret)
126 return 0;
127
128 i++;
129 qca->stats.write_verify_failed++;
130
131 } while (i <= retry);
132
133 return ret;
134}