Merge tag 'nfs-for-4.13-4' of git://git.linux-nfs.org/projects/anna/linux-nfs
[linux-2.6-microblaze.git] / drivers / net / ethernet / qualcomm / qca_7k.c
1 /*
2  *
3  *   Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
4  *   Copyright (c) 2014, I2SE GmbH
5  *
6  *   Permission to use, copy, modify, and/or distribute this software
7  *   for any purpose with or without fee is hereby granted, provided
8  *   that the above copyright notice and this permission notice appear
9  *   in all copies.
10  *
11  *   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
12  *   WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13  *   WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14  *   THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15  *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16  *   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17  *   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18  *   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  *
20  */
21
22 /*   This module implements the Qualcomm Atheros SPI protocol for
23  *   kernel-based SPI device.
24  */
25
26 #include <linux/kernel.h>
27 #include <linux/netdevice.h>
28 #include <linux/spi/spi.h>
29
30 #include "qca_7k.h"
31
32 void
33 qcaspi_spi_error(struct qcaspi *qca)
34 {
35         if (qca->sync != QCASPI_SYNC_READY)
36                 return;
37
38         netdev_err(qca->net_dev, "spi error\n");
39         qca->sync = QCASPI_SYNC_UNKNOWN;
40         qca->stats.spi_err++;
41 }
42
43 int
44 qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result)
45 {
46         __be16 rx_data;
47         __be16 tx_data;
48         struct spi_transfer *transfer;
49         struct spi_message *msg;
50         int ret;
51
52         tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg);
53
54         if (qca->legacy_mode) {
55                 msg = &qca->spi_msg1;
56                 transfer = &qca->spi_xfer1;
57                 transfer->tx_buf = &tx_data;
58                 transfer->rx_buf = NULL;
59                 transfer->len = QCASPI_CMD_LEN;
60                 spi_sync(qca->spi_dev, msg);
61         } else {
62                 msg = &qca->spi_msg2;
63                 transfer = &qca->spi_xfer2[0];
64                 transfer->tx_buf = &tx_data;
65                 transfer->rx_buf = NULL;
66                 transfer->len = QCASPI_CMD_LEN;
67                 transfer = &qca->spi_xfer2[1];
68         }
69         transfer->tx_buf = NULL;
70         transfer->rx_buf = &rx_data;
71         transfer->len = QCASPI_CMD_LEN;
72         ret = spi_sync(qca->spi_dev, msg);
73
74         if (!ret)
75                 ret = msg->status;
76
77         if (ret)
78                 qcaspi_spi_error(qca);
79         else
80                 *result = be16_to_cpu(rx_data);
81
82         return ret;
83 }
84
85 int
86 qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
87 {
88         __be16 tx_data[2];
89         struct spi_transfer *transfer;
90         struct spi_message *msg;
91         int ret;
92
93         tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg);
94         tx_data[1] = cpu_to_be16(value);
95
96         if (qca->legacy_mode) {
97                 msg = &qca->spi_msg1;
98                 transfer = &qca->spi_xfer1;
99                 transfer->tx_buf = &tx_data[0];
100                 transfer->rx_buf = NULL;
101                 transfer->len = QCASPI_CMD_LEN;
102                 spi_sync(qca->spi_dev, msg);
103         } else {
104                 msg = &qca->spi_msg2;
105                 transfer = &qca->spi_xfer2[0];
106                 transfer->tx_buf = &tx_data[0];
107                 transfer->rx_buf = NULL;
108                 transfer->len = QCASPI_CMD_LEN;
109                 transfer = &qca->spi_xfer2[1];
110         }
111         transfer->tx_buf = &tx_data[1];
112         transfer->rx_buf = NULL;
113         transfer->len = QCASPI_CMD_LEN;
114         ret = spi_sync(qca->spi_dev, msg);
115
116         if (!ret)
117                 ret = msg->status;
118
119         if (ret)
120                 qcaspi_spi_error(qca);
121
122         return ret;
123 }