qca_7k.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. /* This module implements the Qualcomm Atheros SPI protocol for
  7. * kernel-based SPI device.
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/netdevice.h>
  11. #include <linux/spi/spi.h>
  12. #include "qca_7k.h"
  13. void
  14. qcaspi_spi_error(struct qcaspi *qca)
  15. {
  16. if (qca->sync != QCASPI_SYNC_READY)
  17. return;
  18. netdev_err(qca->net_dev, "spi error\n");
  19. qca->sync = QCASPI_SYNC_UNKNOWN;
  20. qca->stats.spi_err++;
  21. }
  22. int
  23. qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result)
  24. {
  25. __be16 rx_data;
  26. __be16 tx_data;
  27. struct spi_transfer transfer[2];
  28. struct spi_message msg;
  29. int ret;
  30. memset(transfer, 0, sizeof(transfer));
  31. spi_message_init(&msg);
  32. tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg);
  33. *result = 0;
  34. transfer[0].tx_buf = &tx_data;
  35. transfer[0].len = QCASPI_CMD_LEN;
  36. transfer[1].rx_buf = &rx_data;
  37. transfer[1].len = QCASPI_CMD_LEN;
  38. spi_message_add_tail(&transfer[0], &msg);
  39. if (qca->legacy_mode) {
  40. spi_sync(qca->spi_dev, &msg);
  41. spi_message_init(&msg);
  42. }
  43. spi_message_add_tail(&transfer[1], &msg);
  44. ret = spi_sync(qca->spi_dev, &msg);
  45. if (!ret)
  46. ret = msg.status;
  47. if (ret)
  48. qcaspi_spi_error(qca);
  49. else
  50. *result = be16_to_cpu(rx_data);
  51. return ret;
  52. }
  53. static int
  54. __qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
  55. {
  56. __be16 tx_data[2];
  57. struct spi_transfer transfer[2];
  58. struct spi_message msg;
  59. int ret;
  60. memset(&transfer, 0, sizeof(transfer));
  61. spi_message_init(&msg);
  62. tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg);
  63. tx_data[1] = cpu_to_be16(value);
  64. transfer[0].tx_buf = &tx_data[0];
  65. transfer[0].len = QCASPI_CMD_LEN;
  66. transfer[1].tx_buf = &tx_data[1];
  67. transfer[1].len = QCASPI_CMD_LEN;
  68. spi_message_add_tail(&transfer[0], &msg);
  69. if (qca->legacy_mode) {
  70. spi_sync(qca->spi_dev, &msg);
  71. spi_message_init(&msg);
  72. }
  73. spi_message_add_tail(&transfer[1], &msg);
  74. ret = spi_sync(qca->spi_dev, &msg);
  75. if (!ret)
  76. ret = msg.status;
  77. if (ret)
  78. qcaspi_spi_error(qca);
  79. return ret;
  80. }
  81. int
  82. qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry)
  83. {
  84. int ret, i = 0;
  85. u16 confirmed;
  86. do {
  87. ret = __qcaspi_write_register(qca, reg, value);
  88. if (ret)
  89. return ret;
  90. if (!retry)
  91. return 0;
  92. ret = qcaspi_read_register(qca, reg, &confirmed);
  93. if (ret)
  94. return ret;
  95. ret = confirmed != value;
  96. if (!ret)
  97. return 0;
  98. i++;
  99. qca->stats.write_verify_failed++;
  100. } while (i <= retry);
  101. return ret;
  102. }