Merge tag 'printk-for-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/printk...
[linux-2.6-microblaze.git] / drivers / net / ethernet / qualcomm / qca_7k.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
2 /*
3  *   Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
4  *   Copyright (c) 2014, I2SE GmbH
5  */
6
7 /*   This module implements the Qualcomm Atheros SPI protocol for
8  *   kernel-based SPI device.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/netdevice.h>
13 #include <linux/spi/spi.h>
14
15 #include "qca_7k.h"
16
17 void
18 qcaspi_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
28 int
29 qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result)
30 {
31         __be16 rx_data;
32         __be16 tx_data;
33         struct spi_transfer transfer[2];
34         struct spi_message msg;
35         int ret;
36
37         memset(transfer, 0, sizeof(transfer));
38
39         spi_message_init(&msg);
40
41         tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg);
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);
50
51         if (qca->legacy_mode) {
52                 spi_sync(qca->spi_dev, &msg);
53                 spi_message_init(&msg);
54         }
55         spi_message_add_tail(&transfer[1], &msg);
56         ret = spi_sync(qca->spi_dev, &msg);
57
58         if (!ret)
59                 ret = msg.status;
60
61         if (ret)
62                 qcaspi_spi_error(qca);
63         else
64                 *result = be16_to_cpu(rx_data);
65
66         return ret;
67 }
68
69 static int
70 __qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
71 {
72         __be16 tx_data[2];
73         struct spi_transfer transfer[2];
74         struct spi_message msg;
75         int ret;
76
77         memset(&transfer, 0, sizeof(transfer));
78
79         spi_message_init(&msg);
80
81         tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg);
82         tx_data[1] = cpu_to_be16(value);
83
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);
90         if (qca->legacy_mode) {
91                 spi_sync(qca->spi_dev, &msg);
92                 spi_message_init(&msg);
93         }
94         spi_message_add_tail(&transfer[1], &msg);
95         ret = spi_sync(qca->spi_dev, &msg);
96
97         if (!ret)
98                 ret = msg.status;
99
100         if (ret)
101                 qcaspi_spi_error(qca);
102
103         return ret;
104 }
105
106 int
107 qcaspi_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 }