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/init.h> 27 #include <linux/module.h> 28 #include <linux/moduleparam.h> 29 #include <linux/spi/spi.h> 30 #include <linux/version.h> 31 32 #include "qca_7k.h" 33 34 void 35 qcaspi_spi_error(struct qcaspi *qca) 36 { 37 if (qca->sync != QCASPI_SYNC_READY) 38 return; 39 40 netdev_err(qca->net_dev, "spi error\n"); 41 qca->sync = QCASPI_SYNC_UNKNOWN; 42 qca->stats.spi_err++; 43 } 44 45 int 46 qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result) 47 { 48 __be16 rx_data; 49 __be16 tx_data; 50 struct spi_transfer *transfer; 51 struct spi_message *msg; 52 int ret; 53 54 tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg); 55 56 if (qca->legacy_mode) { 57 msg = &qca->spi_msg1; 58 transfer = &qca->spi_xfer1; 59 transfer->tx_buf = &tx_data; 60 transfer->rx_buf = NULL; 61 transfer->len = QCASPI_CMD_LEN; 62 spi_sync(qca->spi_dev, msg); 63 } else { 64 msg = &qca->spi_msg2; 65 transfer = &qca->spi_xfer2[0]; 66 transfer->tx_buf = &tx_data; 67 transfer->rx_buf = NULL; 68 transfer->len = QCASPI_CMD_LEN; 69 transfer = &qca->spi_xfer2[1]; 70 } 71 transfer->tx_buf = NULL; 72 transfer->rx_buf = &rx_data; 73 transfer->len = QCASPI_CMD_LEN; 74 ret = spi_sync(qca->spi_dev, msg); 75 76 if (!ret) 77 ret = msg->status; 78 79 if (ret) 80 qcaspi_spi_error(qca); 81 else 82 *result = be16_to_cpu(rx_data); 83 84 return ret; 85 } 86 87 int 88 qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) 89 { 90 __be16 tx_data[2]; 91 struct spi_transfer *transfer; 92 struct spi_message *msg; 93 int ret; 94 95 tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg); 96 tx_data[1] = cpu_to_be16(value); 97 98 if (qca->legacy_mode) { 99 msg = &qca->spi_msg1; 100 transfer = &qca->spi_xfer1; 101 transfer->tx_buf = &tx_data[0]; 102 transfer->rx_buf = NULL; 103 transfer->len = QCASPI_CMD_LEN; 104 spi_sync(qca->spi_dev, msg); 105 } else { 106 msg = &qca->spi_msg2; 107 transfer = &qca->spi_xfer2[0]; 108 transfer->tx_buf = &tx_data[0]; 109 transfer->rx_buf = NULL; 110 transfer->len = QCASPI_CMD_LEN; 111 transfer = &qca->spi_xfer2[1]; 112 } 113 transfer->tx_buf = &tx_data[1]; 114 transfer->rx_buf = NULL; 115 transfer->len = QCASPI_CMD_LEN; 116 ret = spi_sync(qca->spi_dev, msg); 117 118 if (!ret) 119 ret = msg->status; 120 121 if (ret) 122 qcaspi_spi_error(qca); 123 124 return ret; 125 } 126 127 int 128 qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) 129 { 130 __be16 tx_data; 131 struct spi_message *msg = &qca->spi_msg1; 132 struct spi_transfer *transfer = &qca->spi_xfer1; 133 int ret; 134 135 tx_data = cpu_to_be16(cmd); 136 transfer->len = sizeof(tx_data); 137 transfer->tx_buf = &tx_data; 138 transfer->rx_buf = NULL; 139 140 ret = spi_sync(qca->spi_dev, msg); 141 142 if (!ret) 143 ret = msg->status; 144 145 if (ret) 146 qcaspi_spi_error(qca); 147 148 return ret; 149 } 150