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[2]; 49 struct spi_message msg; 50 int ret; 51 52 memset(transfer, 0, sizeof(transfer)); 53 54 spi_message_init(&msg); 55 56 tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg); 57 *result = 0; 58 59 transfer[0].tx_buf = &tx_data; 60 transfer[0].len = QCASPI_CMD_LEN; 61 transfer[1].rx_buf = &rx_data; 62 transfer[1].len = QCASPI_CMD_LEN; 63 64 spi_message_add_tail(&transfer[0], &msg); 65 66 if (qca->legacy_mode) { 67 spi_sync(qca->spi_dev, &msg); 68 spi_message_init(&msg); 69 } 70 spi_message_add_tail(&transfer[1], &msg); 71 ret = spi_sync(qca->spi_dev, &msg); 72 73 if (!ret) 74 ret = msg.status; 75 76 if (ret) 77 qcaspi_spi_error(qca); 78 else 79 *result = be16_to_cpu(rx_data); 80 81 return ret; 82 } 83 84 static int 85 __qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) 86 { 87 __be16 tx_data[2]; 88 struct spi_transfer transfer[2]; 89 struct spi_message msg; 90 int ret; 91 92 memset(&transfer, 0, sizeof(transfer)); 93 94 spi_message_init(&msg); 95 96 tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg); 97 tx_data[1] = cpu_to_be16(value); 98 99 transfer[0].tx_buf = &tx_data[0]; 100 transfer[0].len = QCASPI_CMD_LEN; 101 transfer[1].tx_buf = &tx_data[1]; 102 transfer[1].len = QCASPI_CMD_LEN; 103 104 spi_message_add_tail(&transfer[0], &msg); 105 if (qca->legacy_mode) { 106 spi_sync(qca->spi_dev, &msg); 107 spi_message_init(&msg); 108 } 109 spi_message_add_tail(&transfer[1], &msg); 110 ret = spi_sync(qca->spi_dev, &msg); 111 112 if (!ret) 113 ret = msg.status; 114 115 if (ret) 116 qcaspi_spi_error(qca); 117 118 return ret; 119 } 120 121 int 122 qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry) 123 { 124 int ret, i = 0; 125 u16 confirmed; 126 127 do { 128 ret = __qcaspi_write_register(qca, reg, value); 129 if (ret) 130 return ret; 131 132 if (!retry) 133 return 0; 134 135 ret = qcaspi_read_register(qca, reg, &confirmed); 136 if (ret) 137 return ret; 138 139 ret = confirmed != value; 140 if (!ret) 141 return 0; 142 143 i++; 144 qca->stats.write_verify_failed++; 145 146 } while (i <= retry); 147 148 return ret; 149 } 150