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