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 } 124