1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2010 ASIX Electronics Corporation |
4 | * Copyright (c) 2020 Samsung Electronics Co., Ltd. |
5 | * |
6 | * ASIX AX88796C SPI Fast Ethernet Linux driver |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) "ax88796c: " fmt |
10 | |
11 | #include <linux/string.h> |
12 | #include <linux/spi/spi.h> |
13 | |
14 | #include "ax88796c_spi.h" |
15 | |
16 | const u8 ax88796c_rx_cmd_buf[5] = {AX_SPICMD_READ_RXQ, 0xFF, 0xFF, 0xFF, 0xFF}; |
17 | const u8 ax88796c_tx_cmd_buf[4] = {AX_SPICMD_WRITE_TXQ, 0xFF, 0xFF, 0xFF}; |
18 | |
19 | /* driver bus management functions */ |
20 | int axspi_wakeup(struct axspi_data *ax_spi) |
21 | { |
22 | int ret; |
23 | |
24 | ax_spi->cmd_buf[0] = AX_SPICMD_EXIT_PWD; /* OP */ |
25 | ret = spi_write(spi: ax_spi->spi, buf: ax_spi->cmd_buf, len: 1); |
26 | if (ret) |
27 | dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n" , __func__, ret); |
28 | return ret; |
29 | } |
30 | |
31 | int axspi_read_status(struct axspi_data *ax_spi, struct spi_status *status) |
32 | { |
33 | int ret; |
34 | |
35 | /* OP */ |
36 | ax_spi->cmd_buf[0] = AX_SPICMD_READ_STATUS; |
37 | ret = spi_write_then_read(spi: ax_spi->spi, txbuf: ax_spi->cmd_buf, n_tx: 1, rxbuf: (u8 *)status, n_rx: 3); |
38 | if (ret) |
39 | dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n" , __func__, ret); |
40 | else |
41 | le16_to_cpus(&status->isr); |
42 | |
43 | return ret; |
44 | } |
45 | |
46 | int axspi_read_rxq(struct axspi_data *ax_spi, void *data, int len) |
47 | { |
48 | struct spi_transfer *xfer = ax_spi->spi_rx_xfer; |
49 | int ret; |
50 | |
51 | memcpy(ax_spi->cmd_buf, ax88796c_rx_cmd_buf, 5); |
52 | |
53 | xfer->tx_buf = ax_spi->cmd_buf; |
54 | xfer->rx_buf = NULL; |
55 | xfer->len = ax_spi->comp ? 2 : 5; |
56 | xfer->bits_per_word = 8; |
57 | spi_message_add_tail(t: xfer, m: &ax_spi->rx_msg); |
58 | |
59 | xfer++; |
60 | xfer->rx_buf = data; |
61 | xfer->tx_buf = NULL; |
62 | xfer->len = len; |
63 | xfer->bits_per_word = 8; |
64 | spi_message_add_tail(t: xfer, m: &ax_spi->rx_msg); |
65 | ret = spi_sync(spi: ax_spi->spi, message: &ax_spi->rx_msg); |
66 | if (ret) |
67 | dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n" , __func__, ret); |
68 | |
69 | return ret; |
70 | } |
71 | |
72 | int axspi_write_txq(const struct axspi_data *ax_spi, void *data, int len) |
73 | { |
74 | return spi_write(spi: ax_spi->spi, buf: data, len); |
75 | } |
76 | |
77 | u16 axspi_read_reg(struct axspi_data *ax_spi, u8 reg) |
78 | { |
79 | int ret; |
80 | int len = ax_spi->comp ? 3 : 4; |
81 | |
82 | ax_spi->cmd_buf[0] = 0x03; /* OP code read register */ |
83 | ax_spi->cmd_buf[1] = reg; /* register address */ |
84 | ax_spi->cmd_buf[2] = 0xFF; /* dumy cycle */ |
85 | ax_spi->cmd_buf[3] = 0xFF; /* dumy cycle */ |
86 | ret = spi_write_then_read(spi: ax_spi->spi, |
87 | txbuf: ax_spi->cmd_buf, n_tx: len, |
88 | rxbuf: ax_spi->rx_buf, n_rx: 2); |
89 | if (ret) { |
90 | dev_err(&ax_spi->spi->dev, |
91 | "%s() failed: ret = %d\n" , __func__, ret); |
92 | return 0xFFFF; |
93 | } |
94 | |
95 | le16_to_cpus((u16 *)ax_spi->rx_buf); |
96 | |
97 | return *(u16 *)ax_spi->rx_buf; |
98 | } |
99 | |
100 | int axspi_write_reg(struct axspi_data *ax_spi, u8 reg, u16 value) |
101 | { |
102 | int ret; |
103 | |
104 | memset(ax_spi->cmd_buf, 0, sizeof(ax_spi->cmd_buf)); |
105 | ax_spi->cmd_buf[0] = AX_SPICMD_WRITE_REG; /* OP code read register */ |
106 | ax_spi->cmd_buf[1] = reg; /* register address */ |
107 | ax_spi->cmd_buf[2] = value; |
108 | ax_spi->cmd_buf[3] = value >> 8; |
109 | |
110 | ret = spi_write(spi: ax_spi->spi, buf: ax_spi->cmd_buf, len: 4); |
111 | if (ret) |
112 | dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n" , __func__, ret); |
113 | return ret; |
114 | } |
115 | |
116 | |