Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  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
 32void
 33qcaspi_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
 43int
 44qcaspi_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
 84static 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
121int
122qcaspi_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}