linux/drivers/net/ethernet/qualcomm/qca_7k.c
<<
>>
Prefs
   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}
 150