1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for NXP MCR20A 802.15.4 Wireless-PAN Networking controller
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2018 Xue Liu <liuxuenetmail@gmail.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
10*4882a593Smuzhiyun #include <linux/spi/spi.h>
11*4882a593Smuzhiyun #include <linux/workqueue.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/irq.h>
14*4882a593Smuzhiyun #include <linux/skbuff.h>
15*4882a593Smuzhiyun #include <linux/of_gpio.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <linux/ieee802154.h>
18*4882a593Smuzhiyun #include <linux/debugfs.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <net/mac802154.h>
21*4882a593Smuzhiyun #include <net/cfg802154.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/device.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "mcr20a.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define SPI_COMMAND_BUFFER 3
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define REGISTER_READ BIT(7)
30*4882a593Smuzhiyun #define REGISTER_WRITE (0 << 7)
31*4882a593Smuzhiyun #define REGISTER_ACCESS (0 << 6)
32*4882a593Smuzhiyun #define PACKET_BUFF_BURST_ACCESS BIT(6)
33*4882a593Smuzhiyun #define PACKET_BUFF_BYTE_ACCESS BIT(5)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define MCR20A_WRITE_REG(x) (x)
36*4882a593Smuzhiyun #define MCR20A_READ_REG(x) (REGISTER_READ | (x))
37*4882a593Smuzhiyun #define MCR20A_BURST_READ_PACKET_BUF (0xC0)
38*4882a593Smuzhiyun #define MCR20A_BURST_WRITE_PACKET_BUF (0x40)
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #define MCR20A_CMD_REG 0x80
41*4882a593Smuzhiyun #define MCR20A_CMD_REG_MASK 0x3f
42*4882a593Smuzhiyun #define MCR20A_CMD_WRITE 0x40
43*4882a593Smuzhiyun #define MCR20A_CMD_FB 0x20
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /* Number of Interrupt Request Status Register */
46*4882a593Smuzhiyun #define MCR20A_IRQSTS_NUM 2 /* only IRQ_STS1 and IRQ_STS2 */
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* MCR20A CCA Type */
49*4882a593Smuzhiyun enum {
50*4882a593Smuzhiyun MCR20A_CCA_ED, // energy detect - CCA bit not active,
51*4882a593Smuzhiyun // not to be used for T and CCCA sequences
52*4882a593Smuzhiyun MCR20A_CCA_MODE1, // energy detect - CCA bit ACTIVE
53*4882a593Smuzhiyun MCR20A_CCA_MODE2, // 802.15.4 compliant signal detect - CCA bit ACTIVE
54*4882a593Smuzhiyun MCR20A_CCA_MODE3
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun enum {
58*4882a593Smuzhiyun MCR20A_XCVSEQ_IDLE = 0x00,
59*4882a593Smuzhiyun MCR20A_XCVSEQ_RX = 0x01,
60*4882a593Smuzhiyun MCR20A_XCVSEQ_TX = 0x02,
61*4882a593Smuzhiyun MCR20A_XCVSEQ_CCA = 0x03,
62*4882a593Smuzhiyun MCR20A_XCVSEQ_TR = 0x04,
63*4882a593Smuzhiyun MCR20A_XCVSEQ_CCCA = 0x05,
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */
67*4882a593Smuzhiyun #define MCR20A_MIN_CHANNEL (11)
68*4882a593Smuzhiyun #define MCR20A_MAX_CHANNEL (26)
69*4882a593Smuzhiyun #define MCR20A_CHANNEL_SPACING (5)
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* MCR20A CCA Threshold constans */
72*4882a593Smuzhiyun #define MCR20A_MIN_CCA_THRESHOLD (0x6EU)
73*4882a593Smuzhiyun #define MCR20A_MAX_CCA_THRESHOLD (0x00U)
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* version 0C */
76*4882a593Smuzhiyun #define MCR20A_OVERWRITE_VERSION (0x0C)
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* MCR20A PLL configurations */
79*4882a593Smuzhiyun static const u8 PLL_INT[16] = {
80*4882a593Smuzhiyun /* 2405 */ 0x0B, /* 2410 */ 0x0B, /* 2415 */ 0x0B,
81*4882a593Smuzhiyun /* 2420 */ 0x0B, /* 2425 */ 0x0B, /* 2430 */ 0x0B,
82*4882a593Smuzhiyun /* 2435 */ 0x0C, /* 2440 */ 0x0C, /* 2445 */ 0x0C,
83*4882a593Smuzhiyun /* 2450 */ 0x0C, /* 2455 */ 0x0C, /* 2460 */ 0x0C,
84*4882a593Smuzhiyun /* 2465 */ 0x0D, /* 2470 */ 0x0D, /* 2475 */ 0x0D,
85*4882a593Smuzhiyun /* 2480 */ 0x0D
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static const u8 PLL_FRAC[16] = {
89*4882a593Smuzhiyun /* 2405 */ 0x28, /* 2410 */ 0x50, /* 2415 */ 0x78,
90*4882a593Smuzhiyun /* 2420 */ 0xA0, /* 2425 */ 0xC8, /* 2430 */ 0xF0,
91*4882a593Smuzhiyun /* 2435 */ 0x18, /* 2440 */ 0x40, /* 2445 */ 0x68,
92*4882a593Smuzhiyun /* 2450 */ 0x90, /* 2455 */ 0xB8, /* 2460 */ 0xE0,
93*4882a593Smuzhiyun /* 2465 */ 0x08, /* 2470 */ 0x30, /* 2475 */ 0x58,
94*4882a593Smuzhiyun /* 2480 */ 0x80
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun static const struct reg_sequence mar20a_iar_overwrites[] = {
98*4882a593Smuzhiyun { IAR_MISC_PAD_CTRL, 0x02 },
99*4882a593Smuzhiyun { IAR_VCO_CTRL1, 0xB3 },
100*4882a593Smuzhiyun { IAR_VCO_CTRL2, 0x07 },
101*4882a593Smuzhiyun { IAR_PA_TUNING, 0x71 },
102*4882a593Smuzhiyun { IAR_CHF_IBUF, 0x2F },
103*4882a593Smuzhiyun { IAR_CHF_QBUF, 0x2F },
104*4882a593Smuzhiyun { IAR_CHF_IRIN, 0x24 },
105*4882a593Smuzhiyun { IAR_CHF_QRIN, 0x24 },
106*4882a593Smuzhiyun { IAR_CHF_IL, 0x24 },
107*4882a593Smuzhiyun { IAR_CHF_QL, 0x24 },
108*4882a593Smuzhiyun { IAR_CHF_CC1, 0x32 },
109*4882a593Smuzhiyun { IAR_CHF_CCL, 0x1D },
110*4882a593Smuzhiyun { IAR_CHF_CC2, 0x2D },
111*4882a593Smuzhiyun { IAR_CHF_IROUT, 0x24 },
112*4882a593Smuzhiyun { IAR_CHF_QROUT, 0x24 },
113*4882a593Smuzhiyun { IAR_PA_CAL, 0x28 },
114*4882a593Smuzhiyun { IAR_AGC_THR1, 0x55 },
115*4882a593Smuzhiyun { IAR_AGC_THR2, 0x2D },
116*4882a593Smuzhiyun { IAR_ATT_RSSI1, 0x5F },
117*4882a593Smuzhiyun { IAR_ATT_RSSI2, 0x8F },
118*4882a593Smuzhiyun { IAR_RSSI_OFFSET, 0x61 },
119*4882a593Smuzhiyun { IAR_CHF_PMA_GAIN, 0x03 },
120*4882a593Smuzhiyun { IAR_CCA1_THRESH, 0x50 },
121*4882a593Smuzhiyun { IAR_CORR_NVAL, 0x13 },
122*4882a593Smuzhiyun { IAR_ACKDELAY, 0x3D },
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun #define MCR20A_VALID_CHANNELS (0x07FFF800)
126*4882a593Smuzhiyun #define MCR20A_MAX_BUF (127)
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun #define printdev(X) (&X->spi->dev)
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* regmap information for Direct Access Register (DAR) access */
131*4882a593Smuzhiyun #define MCR20A_DAR_WRITE 0x01
132*4882a593Smuzhiyun #define MCR20A_DAR_READ 0x00
133*4882a593Smuzhiyun #define MCR20A_DAR_NUMREGS 0x3F
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* regmap information for Indirect Access Register (IAR) access */
136*4882a593Smuzhiyun #define MCR20A_IAR_ACCESS 0x80
137*4882a593Smuzhiyun #define MCR20A_IAR_NUMREGS 0xBEFF
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Read/Write SPI Commands for DAR and IAR registers. */
140*4882a593Smuzhiyun #define MCR20A_READSHORT(reg) ((reg) << 1)
141*4882a593Smuzhiyun #define MCR20A_WRITESHORT(reg) ((reg) << 1 | 1)
142*4882a593Smuzhiyun #define MCR20A_READLONG(reg) (1 << 15 | (reg) << 5)
143*4882a593Smuzhiyun #define MCR20A_WRITELONG(reg) (1 << 15 | (reg) << 5 | 1 << 4)
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /* Type definitions for link configuration of instantiable layers */
146*4882a593Smuzhiyun #define MCR20A_PHY_INDIRECT_QUEUE_SIZE (12)
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun static bool
mcr20a_dar_writeable(struct device * dev,unsigned int reg)149*4882a593Smuzhiyun mcr20a_dar_writeable(struct device *dev, unsigned int reg)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun switch (reg) {
152*4882a593Smuzhiyun case DAR_IRQ_STS1:
153*4882a593Smuzhiyun case DAR_IRQ_STS2:
154*4882a593Smuzhiyun case DAR_IRQ_STS3:
155*4882a593Smuzhiyun case DAR_PHY_CTRL1:
156*4882a593Smuzhiyun case DAR_PHY_CTRL2:
157*4882a593Smuzhiyun case DAR_PHY_CTRL3:
158*4882a593Smuzhiyun case DAR_PHY_CTRL4:
159*4882a593Smuzhiyun case DAR_SRC_CTRL:
160*4882a593Smuzhiyun case DAR_SRC_ADDRS_SUM_LSB:
161*4882a593Smuzhiyun case DAR_SRC_ADDRS_SUM_MSB:
162*4882a593Smuzhiyun case DAR_T3CMP_LSB:
163*4882a593Smuzhiyun case DAR_T3CMP_MSB:
164*4882a593Smuzhiyun case DAR_T3CMP_USB:
165*4882a593Smuzhiyun case DAR_T2PRIMECMP_LSB:
166*4882a593Smuzhiyun case DAR_T2PRIMECMP_MSB:
167*4882a593Smuzhiyun case DAR_T1CMP_LSB:
168*4882a593Smuzhiyun case DAR_T1CMP_MSB:
169*4882a593Smuzhiyun case DAR_T1CMP_USB:
170*4882a593Smuzhiyun case DAR_T2CMP_LSB:
171*4882a593Smuzhiyun case DAR_T2CMP_MSB:
172*4882a593Smuzhiyun case DAR_T2CMP_USB:
173*4882a593Smuzhiyun case DAR_T4CMP_LSB:
174*4882a593Smuzhiyun case DAR_T4CMP_MSB:
175*4882a593Smuzhiyun case DAR_T4CMP_USB:
176*4882a593Smuzhiyun case DAR_PLL_INT0:
177*4882a593Smuzhiyun case DAR_PLL_FRAC0_LSB:
178*4882a593Smuzhiyun case DAR_PLL_FRAC0_MSB:
179*4882a593Smuzhiyun case DAR_PA_PWR:
180*4882a593Smuzhiyun /* no DAR_ACM */
181*4882a593Smuzhiyun case DAR_OVERWRITE_VER:
182*4882a593Smuzhiyun case DAR_CLK_OUT_CTRL:
183*4882a593Smuzhiyun case DAR_PWR_MODES:
184*4882a593Smuzhiyun return true;
185*4882a593Smuzhiyun default:
186*4882a593Smuzhiyun return false;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun static bool
mcr20a_dar_readable(struct device * dev,unsigned int reg)191*4882a593Smuzhiyun mcr20a_dar_readable(struct device *dev, unsigned int reg)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun bool rc;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /* all writeable are also readable */
196*4882a593Smuzhiyun rc = mcr20a_dar_writeable(dev, reg);
197*4882a593Smuzhiyun if (rc)
198*4882a593Smuzhiyun return rc;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* readonly regs */
201*4882a593Smuzhiyun switch (reg) {
202*4882a593Smuzhiyun case DAR_RX_FRM_LEN:
203*4882a593Smuzhiyun case DAR_CCA1_ED_FNL:
204*4882a593Smuzhiyun case DAR_EVENT_TMR_LSB:
205*4882a593Smuzhiyun case DAR_EVENT_TMR_MSB:
206*4882a593Smuzhiyun case DAR_EVENT_TMR_USB:
207*4882a593Smuzhiyun case DAR_TIMESTAMP_LSB:
208*4882a593Smuzhiyun case DAR_TIMESTAMP_MSB:
209*4882a593Smuzhiyun case DAR_TIMESTAMP_USB:
210*4882a593Smuzhiyun case DAR_SEQ_STATE:
211*4882a593Smuzhiyun case DAR_LQI_VALUE:
212*4882a593Smuzhiyun case DAR_RSSI_CCA_CONT:
213*4882a593Smuzhiyun return true;
214*4882a593Smuzhiyun default:
215*4882a593Smuzhiyun return false;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun static bool
mcr20a_dar_volatile(struct device * dev,unsigned int reg)220*4882a593Smuzhiyun mcr20a_dar_volatile(struct device *dev, unsigned int reg)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun /* can be changed during runtime */
223*4882a593Smuzhiyun switch (reg) {
224*4882a593Smuzhiyun case DAR_IRQ_STS1:
225*4882a593Smuzhiyun case DAR_IRQ_STS2:
226*4882a593Smuzhiyun case DAR_IRQ_STS3:
227*4882a593Smuzhiyun /* use them in spi_async and regmap so it's volatile */
228*4882a593Smuzhiyun return true;
229*4882a593Smuzhiyun default:
230*4882a593Smuzhiyun return false;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun static bool
mcr20a_dar_precious(struct device * dev,unsigned int reg)235*4882a593Smuzhiyun mcr20a_dar_precious(struct device *dev, unsigned int reg)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun /* don't clear irq line on read */
238*4882a593Smuzhiyun switch (reg) {
239*4882a593Smuzhiyun case DAR_IRQ_STS1:
240*4882a593Smuzhiyun case DAR_IRQ_STS2:
241*4882a593Smuzhiyun case DAR_IRQ_STS3:
242*4882a593Smuzhiyun return true;
243*4882a593Smuzhiyun default:
244*4882a593Smuzhiyun return false;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun static const struct regmap_config mcr20a_dar_regmap = {
249*4882a593Smuzhiyun .name = "mcr20a_dar",
250*4882a593Smuzhiyun .reg_bits = 8,
251*4882a593Smuzhiyun .val_bits = 8,
252*4882a593Smuzhiyun .write_flag_mask = REGISTER_ACCESS | REGISTER_WRITE,
253*4882a593Smuzhiyun .read_flag_mask = REGISTER_ACCESS | REGISTER_READ,
254*4882a593Smuzhiyun .cache_type = REGCACHE_RBTREE,
255*4882a593Smuzhiyun .writeable_reg = mcr20a_dar_writeable,
256*4882a593Smuzhiyun .readable_reg = mcr20a_dar_readable,
257*4882a593Smuzhiyun .volatile_reg = mcr20a_dar_volatile,
258*4882a593Smuzhiyun .precious_reg = mcr20a_dar_precious,
259*4882a593Smuzhiyun .fast_io = true,
260*4882a593Smuzhiyun .can_multi_write = true,
261*4882a593Smuzhiyun };
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun static bool
mcr20a_iar_writeable(struct device * dev,unsigned int reg)264*4882a593Smuzhiyun mcr20a_iar_writeable(struct device *dev, unsigned int reg)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun switch (reg) {
267*4882a593Smuzhiyun case IAR_XTAL_TRIM:
268*4882a593Smuzhiyun case IAR_PMC_LP_TRIM:
269*4882a593Smuzhiyun case IAR_MACPANID0_LSB:
270*4882a593Smuzhiyun case IAR_MACPANID0_MSB:
271*4882a593Smuzhiyun case IAR_MACSHORTADDRS0_LSB:
272*4882a593Smuzhiyun case IAR_MACSHORTADDRS0_MSB:
273*4882a593Smuzhiyun case IAR_MACLONGADDRS0_0:
274*4882a593Smuzhiyun case IAR_MACLONGADDRS0_8:
275*4882a593Smuzhiyun case IAR_MACLONGADDRS0_16:
276*4882a593Smuzhiyun case IAR_MACLONGADDRS0_24:
277*4882a593Smuzhiyun case IAR_MACLONGADDRS0_32:
278*4882a593Smuzhiyun case IAR_MACLONGADDRS0_40:
279*4882a593Smuzhiyun case IAR_MACLONGADDRS0_48:
280*4882a593Smuzhiyun case IAR_MACLONGADDRS0_56:
281*4882a593Smuzhiyun case IAR_RX_FRAME_FILTER:
282*4882a593Smuzhiyun case IAR_PLL_INT1:
283*4882a593Smuzhiyun case IAR_PLL_FRAC1_LSB:
284*4882a593Smuzhiyun case IAR_PLL_FRAC1_MSB:
285*4882a593Smuzhiyun case IAR_MACPANID1_LSB:
286*4882a593Smuzhiyun case IAR_MACPANID1_MSB:
287*4882a593Smuzhiyun case IAR_MACSHORTADDRS1_LSB:
288*4882a593Smuzhiyun case IAR_MACSHORTADDRS1_MSB:
289*4882a593Smuzhiyun case IAR_MACLONGADDRS1_0:
290*4882a593Smuzhiyun case IAR_MACLONGADDRS1_8:
291*4882a593Smuzhiyun case IAR_MACLONGADDRS1_16:
292*4882a593Smuzhiyun case IAR_MACLONGADDRS1_24:
293*4882a593Smuzhiyun case IAR_MACLONGADDRS1_32:
294*4882a593Smuzhiyun case IAR_MACLONGADDRS1_40:
295*4882a593Smuzhiyun case IAR_MACLONGADDRS1_48:
296*4882a593Smuzhiyun case IAR_MACLONGADDRS1_56:
297*4882a593Smuzhiyun case IAR_DUAL_PAN_CTRL:
298*4882a593Smuzhiyun case IAR_DUAL_PAN_DWELL:
299*4882a593Smuzhiyun case IAR_CCA1_THRESH:
300*4882a593Smuzhiyun case IAR_CCA1_ED_OFFSET_COMP:
301*4882a593Smuzhiyun case IAR_LQI_OFFSET_COMP:
302*4882a593Smuzhiyun case IAR_CCA_CTRL:
303*4882a593Smuzhiyun case IAR_CCA2_CORR_PEAKS:
304*4882a593Smuzhiyun case IAR_CCA2_CORR_THRESH:
305*4882a593Smuzhiyun case IAR_TMR_PRESCALE:
306*4882a593Smuzhiyun case IAR_ANT_PAD_CTRL:
307*4882a593Smuzhiyun case IAR_MISC_PAD_CTRL:
308*4882a593Smuzhiyun case IAR_BSM_CTRL:
309*4882a593Smuzhiyun case IAR_RNG:
310*4882a593Smuzhiyun case IAR_RX_WTR_MARK:
311*4882a593Smuzhiyun case IAR_SOFT_RESET:
312*4882a593Smuzhiyun case IAR_TXDELAY:
313*4882a593Smuzhiyun case IAR_ACKDELAY:
314*4882a593Smuzhiyun case IAR_CORR_NVAL:
315*4882a593Smuzhiyun case IAR_ANT_AGC_CTRL:
316*4882a593Smuzhiyun case IAR_AGC_THR1:
317*4882a593Smuzhiyun case IAR_AGC_THR2:
318*4882a593Smuzhiyun case IAR_PA_CAL:
319*4882a593Smuzhiyun case IAR_ATT_RSSI1:
320*4882a593Smuzhiyun case IAR_ATT_RSSI2:
321*4882a593Smuzhiyun case IAR_RSSI_OFFSET:
322*4882a593Smuzhiyun case IAR_XTAL_CTRL:
323*4882a593Smuzhiyun case IAR_CHF_PMA_GAIN:
324*4882a593Smuzhiyun case IAR_CHF_IBUF:
325*4882a593Smuzhiyun case IAR_CHF_QBUF:
326*4882a593Smuzhiyun case IAR_CHF_IRIN:
327*4882a593Smuzhiyun case IAR_CHF_QRIN:
328*4882a593Smuzhiyun case IAR_CHF_IL:
329*4882a593Smuzhiyun case IAR_CHF_QL:
330*4882a593Smuzhiyun case IAR_CHF_CC1:
331*4882a593Smuzhiyun case IAR_CHF_CCL:
332*4882a593Smuzhiyun case IAR_CHF_CC2:
333*4882a593Smuzhiyun case IAR_CHF_IROUT:
334*4882a593Smuzhiyun case IAR_CHF_QROUT:
335*4882a593Smuzhiyun case IAR_PA_TUNING:
336*4882a593Smuzhiyun case IAR_VCO_CTRL1:
337*4882a593Smuzhiyun case IAR_VCO_CTRL2:
338*4882a593Smuzhiyun return true;
339*4882a593Smuzhiyun default:
340*4882a593Smuzhiyun return false;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun static bool
mcr20a_iar_readable(struct device * dev,unsigned int reg)345*4882a593Smuzhiyun mcr20a_iar_readable(struct device *dev, unsigned int reg)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun bool rc;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* all writeable are also readable */
350*4882a593Smuzhiyun rc = mcr20a_iar_writeable(dev, reg);
351*4882a593Smuzhiyun if (rc)
352*4882a593Smuzhiyun return rc;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /* readonly regs */
355*4882a593Smuzhiyun switch (reg) {
356*4882a593Smuzhiyun case IAR_PART_ID:
357*4882a593Smuzhiyun case IAR_DUAL_PAN_STS:
358*4882a593Smuzhiyun case IAR_RX_BYTE_COUNT:
359*4882a593Smuzhiyun case IAR_FILTERFAIL_CODE1:
360*4882a593Smuzhiyun case IAR_FILTERFAIL_CODE2:
361*4882a593Smuzhiyun case IAR_RSSI:
362*4882a593Smuzhiyun return true;
363*4882a593Smuzhiyun default:
364*4882a593Smuzhiyun return false;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun static bool
mcr20a_iar_volatile(struct device * dev,unsigned int reg)369*4882a593Smuzhiyun mcr20a_iar_volatile(struct device *dev, unsigned int reg)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun /* can be changed during runtime */
372*4882a593Smuzhiyun switch (reg) {
373*4882a593Smuzhiyun case IAR_DUAL_PAN_STS:
374*4882a593Smuzhiyun case IAR_RX_BYTE_COUNT:
375*4882a593Smuzhiyun case IAR_FILTERFAIL_CODE1:
376*4882a593Smuzhiyun case IAR_FILTERFAIL_CODE2:
377*4882a593Smuzhiyun case IAR_RSSI:
378*4882a593Smuzhiyun return true;
379*4882a593Smuzhiyun default:
380*4882a593Smuzhiyun return false;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun static const struct regmap_config mcr20a_iar_regmap = {
385*4882a593Smuzhiyun .name = "mcr20a_iar",
386*4882a593Smuzhiyun .reg_bits = 16,
387*4882a593Smuzhiyun .val_bits = 8,
388*4882a593Smuzhiyun .write_flag_mask = REGISTER_ACCESS | REGISTER_WRITE | IAR_INDEX,
389*4882a593Smuzhiyun .read_flag_mask = REGISTER_ACCESS | REGISTER_READ | IAR_INDEX,
390*4882a593Smuzhiyun .cache_type = REGCACHE_RBTREE,
391*4882a593Smuzhiyun .writeable_reg = mcr20a_iar_writeable,
392*4882a593Smuzhiyun .readable_reg = mcr20a_iar_readable,
393*4882a593Smuzhiyun .volatile_reg = mcr20a_iar_volatile,
394*4882a593Smuzhiyun .fast_io = true,
395*4882a593Smuzhiyun };
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun struct mcr20a_local {
398*4882a593Smuzhiyun struct spi_device *spi;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun struct ieee802154_hw *hw;
401*4882a593Smuzhiyun struct regmap *regmap_dar;
402*4882a593Smuzhiyun struct regmap *regmap_iar;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun u8 *buf;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun bool is_tx;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /* for writing tx buffer */
409*4882a593Smuzhiyun struct spi_message tx_buf_msg;
410*4882a593Smuzhiyun u8 tx_header[1];
411*4882a593Smuzhiyun /* burst buffer write command */
412*4882a593Smuzhiyun struct spi_transfer tx_xfer_header;
413*4882a593Smuzhiyun u8 tx_len[1];
414*4882a593Smuzhiyun /* len of tx packet */
415*4882a593Smuzhiyun struct spi_transfer tx_xfer_len;
416*4882a593Smuzhiyun /* data of tx packet */
417*4882a593Smuzhiyun struct spi_transfer tx_xfer_buf;
418*4882a593Smuzhiyun struct sk_buff *tx_skb;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun /* for read length rxfifo */
421*4882a593Smuzhiyun struct spi_message reg_msg;
422*4882a593Smuzhiyun u8 reg_cmd[1];
423*4882a593Smuzhiyun u8 reg_data[MCR20A_IRQSTS_NUM];
424*4882a593Smuzhiyun struct spi_transfer reg_xfer_cmd;
425*4882a593Smuzhiyun struct spi_transfer reg_xfer_data;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun /* receive handling */
428*4882a593Smuzhiyun struct spi_message rx_buf_msg;
429*4882a593Smuzhiyun u8 rx_header[1];
430*4882a593Smuzhiyun struct spi_transfer rx_xfer_header;
431*4882a593Smuzhiyun u8 rx_lqi[1];
432*4882a593Smuzhiyun struct spi_transfer rx_xfer_lqi;
433*4882a593Smuzhiyun u8 rx_buf[MCR20A_MAX_BUF];
434*4882a593Smuzhiyun struct spi_transfer rx_xfer_buf;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /* isr handling for reading intstat */
437*4882a593Smuzhiyun struct spi_message irq_msg;
438*4882a593Smuzhiyun u8 irq_header[1];
439*4882a593Smuzhiyun u8 irq_data[MCR20A_IRQSTS_NUM];
440*4882a593Smuzhiyun struct spi_transfer irq_xfer_data;
441*4882a593Smuzhiyun struct spi_transfer irq_xfer_header;
442*4882a593Smuzhiyun };
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun static void
mcr20a_write_tx_buf_complete(void * context)445*4882a593Smuzhiyun mcr20a_write_tx_buf_complete(void *context)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun struct mcr20a_local *lp = context;
448*4882a593Smuzhiyun int ret;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun lp->reg_msg.complete = NULL;
453*4882a593Smuzhiyun lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_PHY_CTRL1);
454*4882a593Smuzhiyun lp->reg_data[0] = MCR20A_XCVSEQ_TX;
455*4882a593Smuzhiyun lp->reg_xfer_data.len = 1;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun ret = spi_async(lp->spi, &lp->reg_msg);
458*4882a593Smuzhiyun if (ret)
459*4882a593Smuzhiyun dev_err(printdev(lp), "failed to set SEQ TX\n");
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun static int
mcr20a_xmit(struct ieee802154_hw * hw,struct sk_buff * skb)463*4882a593Smuzhiyun mcr20a_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun lp->tx_skb = skb;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun print_hex_dump_debug("mcr20a tx: ", DUMP_PREFIX_OFFSET, 16, 1,
472*4882a593Smuzhiyun skb->data, skb->len, 0);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun lp->is_tx = 1;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun lp->reg_msg.complete = NULL;
477*4882a593Smuzhiyun lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_PHY_CTRL1);
478*4882a593Smuzhiyun lp->reg_data[0] = MCR20A_XCVSEQ_IDLE;
479*4882a593Smuzhiyun lp->reg_xfer_data.len = 1;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun return spi_async(lp->spi, &lp->reg_msg);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun static int
mcr20a_ed(struct ieee802154_hw * hw,u8 * level)485*4882a593Smuzhiyun mcr20a_ed(struct ieee802154_hw *hw, u8 *level)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun WARN_ON(!level);
488*4882a593Smuzhiyun *level = 0xbe;
489*4882a593Smuzhiyun return 0;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun static int
mcr20a_set_channel(struct ieee802154_hw * hw,u8 page,u8 channel)493*4882a593Smuzhiyun mcr20a_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
496*4882a593Smuzhiyun int ret;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun /* freqency = ((PLL_INT+64) + (PLL_FRAC/65536)) * 32 MHz */
501*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_PLL_INT0, PLL_INT[channel - 11]);
502*4882a593Smuzhiyun if (ret)
503*4882a593Smuzhiyun return ret;
504*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_PLL_FRAC0_LSB, 0x00);
505*4882a593Smuzhiyun if (ret)
506*4882a593Smuzhiyun return ret;
507*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_PLL_FRAC0_MSB,
508*4882a593Smuzhiyun PLL_FRAC[channel - 11]);
509*4882a593Smuzhiyun if (ret)
510*4882a593Smuzhiyun return ret;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun return 0;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun static int
mcr20a_start(struct ieee802154_hw * hw)516*4882a593Smuzhiyun mcr20a_start(struct ieee802154_hw *hw)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
519*4882a593Smuzhiyun int ret;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /* No slotted operation */
524*4882a593Smuzhiyun dev_dbg(printdev(lp), "no slotted operation\n");
525*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
526*4882a593Smuzhiyun DAR_PHY_CTRL1_SLOTTED, 0x0);
527*4882a593Smuzhiyun if (ret < 0)
528*4882a593Smuzhiyun return ret;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* enable irq */
531*4882a593Smuzhiyun enable_irq(lp->spi->irq);
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun /* Unmask SEQ interrupt */
534*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL2,
535*4882a593Smuzhiyun DAR_PHY_CTRL2_SEQMSK, 0x0);
536*4882a593Smuzhiyun if (ret < 0)
537*4882a593Smuzhiyun return ret;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun /* Start the RX sequence */
540*4882a593Smuzhiyun dev_dbg(printdev(lp), "start the RX sequence\n");
541*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
542*4882a593Smuzhiyun DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX);
543*4882a593Smuzhiyun if (ret < 0)
544*4882a593Smuzhiyun return ret;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun return 0;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun static void
mcr20a_stop(struct ieee802154_hw * hw)550*4882a593Smuzhiyun mcr20a_stop(struct ieee802154_hw *hw)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /* stop all running sequence */
557*4882a593Smuzhiyun regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
558*4882a593Smuzhiyun DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE);
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun /* disable irq */
561*4882a593Smuzhiyun disable_irq(lp->spi->irq);
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun static int
mcr20a_set_hw_addr_filt(struct ieee802154_hw * hw,struct ieee802154_hw_addr_filt * filt,unsigned long changed)565*4882a593Smuzhiyun mcr20a_set_hw_addr_filt(struct ieee802154_hw *hw,
566*4882a593Smuzhiyun struct ieee802154_hw_addr_filt *filt,
567*4882a593Smuzhiyun unsigned long changed)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
574*4882a593Smuzhiyun u16 addr = le16_to_cpu(filt->short_addr);
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun regmap_write(lp->regmap_iar, IAR_MACSHORTADDRS0_LSB, addr);
577*4882a593Smuzhiyun regmap_write(lp->regmap_iar, IAR_MACSHORTADDRS0_MSB, addr >> 8);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun if (changed & IEEE802154_AFILT_PANID_CHANGED) {
581*4882a593Smuzhiyun u16 pan = le16_to_cpu(filt->pan_id);
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun regmap_write(lp->regmap_iar, IAR_MACPANID0_LSB, pan);
584*4882a593Smuzhiyun regmap_write(lp->regmap_iar, IAR_MACPANID0_MSB, pan >> 8);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
588*4882a593Smuzhiyun u8 addr[8], i;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun memcpy(addr, &filt->ieee_addr, 8);
591*4882a593Smuzhiyun for (i = 0; i < 8; i++)
592*4882a593Smuzhiyun regmap_write(lp->regmap_iar,
593*4882a593Smuzhiyun IAR_MACLONGADDRS0_0 + i, addr[i]);
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun if (changed & IEEE802154_AFILT_PANC_CHANGED) {
597*4882a593Smuzhiyun if (filt->pan_coord) {
598*4882a593Smuzhiyun regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
599*4882a593Smuzhiyun DAR_PHY_CTRL4_PANCORDNTR0, 0x10);
600*4882a593Smuzhiyun } else {
601*4882a593Smuzhiyun regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
602*4882a593Smuzhiyun DAR_PHY_CTRL4_PANCORDNTR0, 0x00);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /* -30 dBm to 10 dBm */
610*4882a593Smuzhiyun #define MCR20A_MAX_TX_POWERS 0x14
611*4882a593Smuzhiyun static const s32 mcr20a_powers[MCR20A_MAX_TX_POWERS + 1] = {
612*4882a593Smuzhiyun -3000, -2800, -2600, -2400, -2200, -2000, -1800, -1600, -1400,
613*4882a593Smuzhiyun -1200, -1000, -800, -600, -400, -200, 0, 200, 400, 600, 800, 1000
614*4882a593Smuzhiyun };
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun static int
mcr20a_set_txpower(struct ieee802154_hw * hw,s32 mbm)617*4882a593Smuzhiyun mcr20a_set_txpower(struct ieee802154_hw *hw, s32 mbm)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
620*4882a593Smuzhiyun u32 i;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s(%d)\n", __func__, mbm);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
625*4882a593Smuzhiyun if (lp->hw->phy->supported.tx_powers[i] == mbm)
626*4882a593Smuzhiyun return regmap_write(lp->regmap_dar, DAR_PA_PWR,
627*4882a593Smuzhiyun ((i + 8) & 0x1F));
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun return -EINVAL;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun #define MCR20A_MAX_ED_LEVELS MCR20A_MIN_CCA_THRESHOLD
634*4882a593Smuzhiyun static s32 mcr20a_ed_levels[MCR20A_MAX_ED_LEVELS + 1];
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun static int
mcr20a_set_cca_mode(struct ieee802154_hw * hw,const struct wpan_phy_cca * cca)637*4882a593Smuzhiyun mcr20a_set_cca_mode(struct ieee802154_hw *hw,
638*4882a593Smuzhiyun const struct wpan_phy_cca *cca)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
641*4882a593Smuzhiyun unsigned int cca_mode = 0xff;
642*4882a593Smuzhiyun bool cca_mode_and = false;
643*4882a593Smuzhiyun int ret;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /* mapping 802.15.4 to driver spec */
648*4882a593Smuzhiyun switch (cca->mode) {
649*4882a593Smuzhiyun case NL802154_CCA_ENERGY:
650*4882a593Smuzhiyun cca_mode = MCR20A_CCA_MODE1;
651*4882a593Smuzhiyun break;
652*4882a593Smuzhiyun case NL802154_CCA_CARRIER:
653*4882a593Smuzhiyun cca_mode = MCR20A_CCA_MODE2;
654*4882a593Smuzhiyun break;
655*4882a593Smuzhiyun case NL802154_CCA_ENERGY_CARRIER:
656*4882a593Smuzhiyun switch (cca->opt) {
657*4882a593Smuzhiyun case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
658*4882a593Smuzhiyun cca_mode = MCR20A_CCA_MODE3;
659*4882a593Smuzhiyun cca_mode_and = true;
660*4882a593Smuzhiyun break;
661*4882a593Smuzhiyun case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
662*4882a593Smuzhiyun cca_mode = MCR20A_CCA_MODE3;
663*4882a593Smuzhiyun cca_mode_and = false;
664*4882a593Smuzhiyun break;
665*4882a593Smuzhiyun default:
666*4882a593Smuzhiyun return -EINVAL;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun break;
669*4882a593Smuzhiyun default:
670*4882a593Smuzhiyun return -EINVAL;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
673*4882a593Smuzhiyun DAR_PHY_CTRL4_CCATYPE_MASK,
674*4882a593Smuzhiyun cca_mode << DAR_PHY_CTRL4_CCATYPE_SHIFT);
675*4882a593Smuzhiyun if (ret < 0)
676*4882a593Smuzhiyun return ret;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun if (cca_mode == MCR20A_CCA_MODE3) {
679*4882a593Smuzhiyun if (cca_mode_and) {
680*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_iar, IAR_CCA_CTRL,
681*4882a593Smuzhiyun IAR_CCA_CTRL_CCA3_AND_NOT_OR,
682*4882a593Smuzhiyun 0x08);
683*4882a593Smuzhiyun } else {
684*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_iar,
685*4882a593Smuzhiyun IAR_CCA_CTRL,
686*4882a593Smuzhiyun IAR_CCA_CTRL_CCA3_AND_NOT_OR,
687*4882a593Smuzhiyun 0x00);
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun if (ret < 0)
690*4882a593Smuzhiyun return ret;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun return ret;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun static int
mcr20a_set_cca_ed_level(struct ieee802154_hw * hw,s32 mbm)697*4882a593Smuzhiyun mcr20a_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
700*4882a593Smuzhiyun u32 i;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
705*4882a593Smuzhiyun if (hw->phy->supported.cca_ed_levels[i] == mbm)
706*4882a593Smuzhiyun return regmap_write(lp->regmap_iar, IAR_CCA1_THRESH, i);
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun return 0;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun static int
mcr20a_set_promiscuous_mode(struct ieee802154_hw * hw,const bool on)713*4882a593Smuzhiyun mcr20a_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun struct mcr20a_local *lp = hw->priv;
716*4882a593Smuzhiyun int ret;
717*4882a593Smuzhiyun u8 rx_frame_filter_reg = 0x0;
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s(%d)\n", __func__, on);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun if (on) {
722*4882a593Smuzhiyun /* All frame types accepted*/
723*4882a593Smuzhiyun rx_frame_filter_reg &= ~(IAR_RX_FRAME_FLT_FRM_VER);
724*4882a593Smuzhiyun rx_frame_filter_reg |= (IAR_RX_FRAME_FLT_ACK_FT |
725*4882a593Smuzhiyun IAR_RX_FRAME_FLT_NS_FT);
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
728*4882a593Smuzhiyun DAR_PHY_CTRL4_PROMISCUOUS,
729*4882a593Smuzhiyun DAR_PHY_CTRL4_PROMISCUOUS);
730*4882a593Smuzhiyun if (ret < 0)
731*4882a593Smuzhiyun return ret;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER,
734*4882a593Smuzhiyun rx_frame_filter_reg);
735*4882a593Smuzhiyun if (ret < 0)
736*4882a593Smuzhiyun return ret;
737*4882a593Smuzhiyun } else {
738*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
739*4882a593Smuzhiyun DAR_PHY_CTRL4_PROMISCUOUS, 0x0);
740*4882a593Smuzhiyun if (ret < 0)
741*4882a593Smuzhiyun return ret;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER,
744*4882a593Smuzhiyun IAR_RX_FRAME_FLT_FRM_VER |
745*4882a593Smuzhiyun IAR_RX_FRAME_FLT_BEACON_FT |
746*4882a593Smuzhiyun IAR_RX_FRAME_FLT_DATA_FT |
747*4882a593Smuzhiyun IAR_RX_FRAME_FLT_CMD_FT);
748*4882a593Smuzhiyun if (ret < 0)
749*4882a593Smuzhiyun return ret;
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun return 0;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun static const struct ieee802154_ops mcr20a_hw_ops = {
756*4882a593Smuzhiyun .owner = THIS_MODULE,
757*4882a593Smuzhiyun .xmit_async = mcr20a_xmit,
758*4882a593Smuzhiyun .ed = mcr20a_ed,
759*4882a593Smuzhiyun .set_channel = mcr20a_set_channel,
760*4882a593Smuzhiyun .start = mcr20a_start,
761*4882a593Smuzhiyun .stop = mcr20a_stop,
762*4882a593Smuzhiyun .set_hw_addr_filt = mcr20a_set_hw_addr_filt,
763*4882a593Smuzhiyun .set_txpower = mcr20a_set_txpower,
764*4882a593Smuzhiyun .set_cca_mode = mcr20a_set_cca_mode,
765*4882a593Smuzhiyun .set_cca_ed_level = mcr20a_set_cca_ed_level,
766*4882a593Smuzhiyun .set_promiscuous_mode = mcr20a_set_promiscuous_mode,
767*4882a593Smuzhiyun };
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun static int
mcr20a_request_rx(struct mcr20a_local * lp)770*4882a593Smuzhiyun mcr20a_request_rx(struct mcr20a_local *lp)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun /* Start the RX sequence */
775*4882a593Smuzhiyun regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1,
776*4882a593Smuzhiyun DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX);
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun return 0;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun static void
mcr20a_handle_rx_read_buf_complete(void * context)782*4882a593Smuzhiyun mcr20a_handle_rx_read_buf_complete(void *context)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun struct mcr20a_local *lp = context;
785*4882a593Smuzhiyun u8 len = lp->reg_data[0] & DAR_RX_FRAME_LENGTH_MASK;
786*4882a593Smuzhiyun struct sk_buff *skb;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun dev_dbg(printdev(lp), "RX is done\n");
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun if (!ieee802154_is_valid_psdu_len(len)) {
793*4882a593Smuzhiyun dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
794*4882a593Smuzhiyun len = IEEE802154_MTU;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun len = len - 2; /* get rid of frame check field */
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun skb = dev_alloc_skb(len);
800*4882a593Smuzhiyun if (!skb)
801*4882a593Smuzhiyun return;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun __skb_put_data(skb, lp->rx_buf, len);
804*4882a593Smuzhiyun ieee802154_rx_irqsafe(lp->hw, skb, lp->rx_lqi[0]);
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun print_hex_dump_debug("mcr20a rx: ", DUMP_PREFIX_OFFSET, 16, 1,
807*4882a593Smuzhiyun lp->rx_buf, len, 0);
808*4882a593Smuzhiyun pr_debug("mcr20a rx: lqi: %02hhx\n", lp->rx_lqi[0]);
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun /* start RX sequence */
811*4882a593Smuzhiyun mcr20a_request_rx(lp);
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun static void
mcr20a_handle_rx_read_len_complete(void * context)815*4882a593Smuzhiyun mcr20a_handle_rx_read_len_complete(void *context)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun struct mcr20a_local *lp = context;
818*4882a593Smuzhiyun u8 len;
819*4882a593Smuzhiyun int ret;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun /* get the length of received frame */
824*4882a593Smuzhiyun len = lp->reg_data[0] & DAR_RX_FRAME_LENGTH_MASK;
825*4882a593Smuzhiyun dev_dbg(printdev(lp), "frame len : %d\n", len);
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun /* prepare to read the rx buf */
828*4882a593Smuzhiyun lp->rx_buf_msg.complete = mcr20a_handle_rx_read_buf_complete;
829*4882a593Smuzhiyun lp->rx_header[0] = MCR20A_BURST_READ_PACKET_BUF;
830*4882a593Smuzhiyun lp->rx_xfer_buf.len = len;
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun ret = spi_async(lp->spi, &lp->rx_buf_msg);
833*4882a593Smuzhiyun if (ret)
834*4882a593Smuzhiyun dev_err(printdev(lp), "failed to read rx buffer length\n");
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun static int
mcr20a_handle_rx(struct mcr20a_local * lp)838*4882a593Smuzhiyun mcr20a_handle_rx(struct mcr20a_local *lp)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
841*4882a593Smuzhiyun lp->reg_msg.complete = mcr20a_handle_rx_read_len_complete;
842*4882a593Smuzhiyun lp->reg_cmd[0] = MCR20A_READ_REG(DAR_RX_FRM_LEN);
843*4882a593Smuzhiyun lp->reg_xfer_data.len = 1;
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun return spi_async(lp->spi, &lp->reg_msg);
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun static int
mcr20a_handle_tx_complete(struct mcr20a_local * lp)849*4882a593Smuzhiyun mcr20a_handle_tx_complete(struct mcr20a_local *lp)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun ieee802154_xmit_complete(lp->hw, lp->tx_skb, false);
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun return mcr20a_request_rx(lp);
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun static int
mcr20a_handle_tx(struct mcr20a_local * lp)859*4882a593Smuzhiyun mcr20a_handle_tx(struct mcr20a_local *lp)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun int ret;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun /* write tx buffer */
866*4882a593Smuzhiyun lp->tx_header[0] = MCR20A_BURST_WRITE_PACKET_BUF;
867*4882a593Smuzhiyun /* add 2 bytes of FCS */
868*4882a593Smuzhiyun lp->tx_len[0] = lp->tx_skb->len + 2;
869*4882a593Smuzhiyun lp->tx_xfer_buf.tx_buf = lp->tx_skb->data;
870*4882a593Smuzhiyun /* add 1 byte psduLength */
871*4882a593Smuzhiyun lp->tx_xfer_buf.len = lp->tx_skb->len + 1;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun ret = spi_async(lp->spi, &lp->tx_buf_msg);
874*4882a593Smuzhiyun if (ret) {
875*4882a593Smuzhiyun dev_err(printdev(lp), "SPI write Failed for TX buf\n");
876*4882a593Smuzhiyun return ret;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun return 0;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun static void
mcr20a_irq_clean_complete(void * context)883*4882a593Smuzhiyun mcr20a_irq_clean_complete(void *context)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun struct mcr20a_local *lp = context;
886*4882a593Smuzhiyun u8 seq_state = lp->irq_data[DAR_IRQ_STS1] & DAR_PHY_CTRL1_XCVSEQ_MASK;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun enable_irq(lp->spi->irq);
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun dev_dbg(printdev(lp), "IRQ STA1 (%02x) STA2 (%02x)\n",
893*4882a593Smuzhiyun lp->irq_data[DAR_IRQ_STS1], lp->irq_data[DAR_IRQ_STS2]);
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun switch (seq_state) {
896*4882a593Smuzhiyun /* TX IRQ, RX IRQ and SEQ IRQ */
897*4882a593Smuzhiyun case (DAR_IRQSTS1_TXIRQ | DAR_IRQSTS1_SEQIRQ):
898*4882a593Smuzhiyun if (lp->is_tx) {
899*4882a593Smuzhiyun lp->is_tx = 0;
900*4882a593Smuzhiyun dev_dbg(printdev(lp), "TX is done. No ACK\n");
901*4882a593Smuzhiyun mcr20a_handle_tx_complete(lp);
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun break;
904*4882a593Smuzhiyun case (DAR_IRQSTS1_RXIRQ | DAR_IRQSTS1_SEQIRQ):
905*4882a593Smuzhiyun /* rx is starting */
906*4882a593Smuzhiyun dev_dbg(printdev(lp), "RX is starting\n");
907*4882a593Smuzhiyun mcr20a_handle_rx(lp);
908*4882a593Smuzhiyun break;
909*4882a593Smuzhiyun case (DAR_IRQSTS1_RXIRQ | DAR_IRQSTS1_TXIRQ | DAR_IRQSTS1_SEQIRQ):
910*4882a593Smuzhiyun if (lp->is_tx) {
911*4882a593Smuzhiyun /* tx is done */
912*4882a593Smuzhiyun lp->is_tx = 0;
913*4882a593Smuzhiyun dev_dbg(printdev(lp), "TX is done. Get ACK\n");
914*4882a593Smuzhiyun mcr20a_handle_tx_complete(lp);
915*4882a593Smuzhiyun } else {
916*4882a593Smuzhiyun /* rx is starting */
917*4882a593Smuzhiyun dev_dbg(printdev(lp), "RX is starting\n");
918*4882a593Smuzhiyun mcr20a_handle_rx(lp);
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun break;
921*4882a593Smuzhiyun case (DAR_IRQSTS1_SEQIRQ):
922*4882a593Smuzhiyun if (lp->is_tx) {
923*4882a593Smuzhiyun dev_dbg(printdev(lp), "TX is starting\n");
924*4882a593Smuzhiyun mcr20a_handle_tx(lp);
925*4882a593Smuzhiyun } else {
926*4882a593Smuzhiyun dev_dbg(printdev(lp), "MCR20A is stop\n");
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun break;
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun
mcr20a_irq_status_complete(void * context)932*4882a593Smuzhiyun static void mcr20a_irq_status_complete(void *context)
933*4882a593Smuzhiyun {
934*4882a593Smuzhiyun int ret;
935*4882a593Smuzhiyun struct mcr20a_local *lp = context;
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
938*4882a593Smuzhiyun regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1,
939*4882a593Smuzhiyun DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE);
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun lp->reg_msg.complete = mcr20a_irq_clean_complete;
942*4882a593Smuzhiyun lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_IRQ_STS1);
943*4882a593Smuzhiyun memcpy(lp->reg_data, lp->irq_data, MCR20A_IRQSTS_NUM);
944*4882a593Smuzhiyun lp->reg_xfer_data.len = MCR20A_IRQSTS_NUM;
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun ret = spi_async(lp->spi, &lp->reg_msg);
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun if (ret)
949*4882a593Smuzhiyun dev_err(printdev(lp), "failed to clean irq status\n");
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
mcr20a_irq_isr(int irq,void * data)952*4882a593Smuzhiyun static irqreturn_t mcr20a_irq_isr(int irq, void *data)
953*4882a593Smuzhiyun {
954*4882a593Smuzhiyun struct mcr20a_local *lp = data;
955*4882a593Smuzhiyun int ret;
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun disable_irq_nosync(irq);
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun lp->irq_header[0] = MCR20A_READ_REG(DAR_IRQ_STS1);
960*4882a593Smuzhiyun /* read IRQSTSx */
961*4882a593Smuzhiyun ret = spi_async(lp->spi, &lp->irq_msg);
962*4882a593Smuzhiyun if (ret) {
963*4882a593Smuzhiyun enable_irq(irq);
964*4882a593Smuzhiyun return IRQ_NONE;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun return IRQ_HANDLED;
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
mcr20a_hw_setup(struct mcr20a_local * lp)970*4882a593Smuzhiyun static void mcr20a_hw_setup(struct mcr20a_local *lp)
971*4882a593Smuzhiyun {
972*4882a593Smuzhiyun u8 i;
973*4882a593Smuzhiyun struct ieee802154_hw *hw = lp->hw;
974*4882a593Smuzhiyun struct wpan_phy *phy = lp->hw->phy;
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun phy->symbol_duration = 16;
979*4882a593Smuzhiyun phy->lifs_period = 40 * phy->symbol_duration;
980*4882a593Smuzhiyun phy->sifs_period = 12 * phy->symbol_duration;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
983*4882a593Smuzhiyun IEEE802154_HW_AFILT |
984*4882a593Smuzhiyun IEEE802154_HW_PROMISCUOUS;
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL |
987*4882a593Smuzhiyun WPAN_PHY_FLAG_CCA_MODE;
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
990*4882a593Smuzhiyun BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER);
991*4882a593Smuzhiyun phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
992*4882a593Smuzhiyun BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun /* initiating cca_ed_levels */
995*4882a593Smuzhiyun for (i = MCR20A_MAX_CCA_THRESHOLD; i < MCR20A_MIN_CCA_THRESHOLD + 1;
996*4882a593Smuzhiyun ++i) {
997*4882a593Smuzhiyun mcr20a_ed_levels[i] = -i * 100;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun phy->supported.cca_ed_levels = mcr20a_ed_levels;
1001*4882a593Smuzhiyun phy->supported.cca_ed_levels_size = ARRAY_SIZE(mcr20a_ed_levels);
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun phy->cca.mode = NL802154_CCA_ENERGY;
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun phy->supported.channels[0] = MCR20A_VALID_CHANNELS;
1006*4882a593Smuzhiyun phy->current_page = 0;
1007*4882a593Smuzhiyun /* MCR20A default reset value */
1008*4882a593Smuzhiyun phy->current_channel = 20;
1009*4882a593Smuzhiyun phy->symbol_duration = 16;
1010*4882a593Smuzhiyun phy->supported.tx_powers = mcr20a_powers;
1011*4882a593Smuzhiyun phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
1012*4882a593Smuzhiyun phy->cca_ed_level = phy->supported.cca_ed_levels[75];
1013*4882a593Smuzhiyun phy->transmit_power = phy->supported.tx_powers[0x0F];
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun static void
mcr20a_setup_tx_spi_messages(struct mcr20a_local * lp)1017*4882a593Smuzhiyun mcr20a_setup_tx_spi_messages(struct mcr20a_local *lp)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun spi_message_init(&lp->tx_buf_msg);
1020*4882a593Smuzhiyun lp->tx_buf_msg.context = lp;
1021*4882a593Smuzhiyun lp->tx_buf_msg.complete = mcr20a_write_tx_buf_complete;
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun lp->tx_xfer_header.len = 1;
1024*4882a593Smuzhiyun lp->tx_xfer_header.tx_buf = lp->tx_header;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun lp->tx_xfer_len.len = 1;
1027*4882a593Smuzhiyun lp->tx_xfer_len.tx_buf = lp->tx_len;
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun spi_message_add_tail(&lp->tx_xfer_header, &lp->tx_buf_msg);
1030*4882a593Smuzhiyun spi_message_add_tail(&lp->tx_xfer_len, &lp->tx_buf_msg);
1031*4882a593Smuzhiyun spi_message_add_tail(&lp->tx_xfer_buf, &lp->tx_buf_msg);
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun static void
mcr20a_setup_rx_spi_messages(struct mcr20a_local * lp)1035*4882a593Smuzhiyun mcr20a_setup_rx_spi_messages(struct mcr20a_local *lp)
1036*4882a593Smuzhiyun {
1037*4882a593Smuzhiyun spi_message_init(&lp->reg_msg);
1038*4882a593Smuzhiyun lp->reg_msg.context = lp;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun lp->reg_xfer_cmd.len = 1;
1041*4882a593Smuzhiyun lp->reg_xfer_cmd.tx_buf = lp->reg_cmd;
1042*4882a593Smuzhiyun lp->reg_xfer_cmd.rx_buf = lp->reg_cmd;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun lp->reg_xfer_data.rx_buf = lp->reg_data;
1045*4882a593Smuzhiyun lp->reg_xfer_data.tx_buf = lp->reg_data;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun spi_message_add_tail(&lp->reg_xfer_cmd, &lp->reg_msg);
1048*4882a593Smuzhiyun spi_message_add_tail(&lp->reg_xfer_data, &lp->reg_msg);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun spi_message_init(&lp->rx_buf_msg);
1051*4882a593Smuzhiyun lp->rx_buf_msg.context = lp;
1052*4882a593Smuzhiyun lp->rx_buf_msg.complete = mcr20a_handle_rx_read_buf_complete;
1053*4882a593Smuzhiyun lp->rx_xfer_header.len = 1;
1054*4882a593Smuzhiyun lp->rx_xfer_header.tx_buf = lp->rx_header;
1055*4882a593Smuzhiyun lp->rx_xfer_header.rx_buf = lp->rx_header;
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun lp->rx_xfer_buf.rx_buf = lp->rx_buf;
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun lp->rx_xfer_lqi.len = 1;
1060*4882a593Smuzhiyun lp->rx_xfer_lqi.rx_buf = lp->rx_lqi;
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun spi_message_add_tail(&lp->rx_xfer_header, &lp->rx_buf_msg);
1063*4882a593Smuzhiyun spi_message_add_tail(&lp->rx_xfer_buf, &lp->rx_buf_msg);
1064*4882a593Smuzhiyun spi_message_add_tail(&lp->rx_xfer_lqi, &lp->rx_buf_msg);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun static void
mcr20a_setup_irq_spi_messages(struct mcr20a_local * lp)1068*4882a593Smuzhiyun mcr20a_setup_irq_spi_messages(struct mcr20a_local *lp)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun spi_message_init(&lp->irq_msg);
1071*4882a593Smuzhiyun lp->irq_msg.context = lp;
1072*4882a593Smuzhiyun lp->irq_msg.complete = mcr20a_irq_status_complete;
1073*4882a593Smuzhiyun lp->irq_xfer_header.len = 1;
1074*4882a593Smuzhiyun lp->irq_xfer_header.tx_buf = lp->irq_header;
1075*4882a593Smuzhiyun lp->irq_xfer_header.rx_buf = lp->irq_header;
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun lp->irq_xfer_data.len = MCR20A_IRQSTS_NUM;
1078*4882a593Smuzhiyun lp->irq_xfer_data.rx_buf = lp->irq_data;
1079*4882a593Smuzhiyun
1080*4882a593Smuzhiyun spi_message_add_tail(&lp->irq_xfer_header, &lp->irq_msg);
1081*4882a593Smuzhiyun spi_message_add_tail(&lp->irq_xfer_data, &lp->irq_msg);
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun static int
mcr20a_phy_init(struct mcr20a_local * lp)1085*4882a593Smuzhiyun mcr20a_phy_init(struct mcr20a_local *lp)
1086*4882a593Smuzhiyun {
1087*4882a593Smuzhiyun u8 index;
1088*4882a593Smuzhiyun unsigned int phy_reg = 0;
1089*4882a593Smuzhiyun int ret;
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun dev_dbg(printdev(lp), "%s\n", __func__);
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun /* Disable Tristate on COCO MISO for SPI reads */
1094*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_MISC_PAD_CTRL, 0x02);
1095*4882a593Smuzhiyun if (ret)
1096*4882a593Smuzhiyun goto err_ret;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun /* Clear all PP IRQ bits in IRQSTS1 to avoid unexpected interrupts
1099*4882a593Smuzhiyun * immediately after init
1100*4882a593Smuzhiyun */
1101*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS1, 0xEF);
1102*4882a593Smuzhiyun if (ret)
1103*4882a593Smuzhiyun goto err_ret;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun /* Clear all PP IRQ bits in IRQSTS2 */
1106*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS2,
1107*4882a593Smuzhiyun DAR_IRQSTS2_ASM_IRQ | DAR_IRQSTS2_PB_ERR_IRQ |
1108*4882a593Smuzhiyun DAR_IRQSTS2_WAKE_IRQ);
1109*4882a593Smuzhiyun if (ret)
1110*4882a593Smuzhiyun goto err_ret;
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun /* Disable all timer interrupts */
1113*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS3, 0xFF);
1114*4882a593Smuzhiyun if (ret)
1115*4882a593Smuzhiyun goto err_ret;
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun /* PHY_CTRL1 : default HW settings + AUTOACK enabled */
1118*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
1119*4882a593Smuzhiyun DAR_PHY_CTRL1_AUTOACK, DAR_PHY_CTRL1_AUTOACK);
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun /* PHY_CTRL2 : disable all interrupts */
1122*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_PHY_CTRL2, 0xFF);
1123*4882a593Smuzhiyun if (ret)
1124*4882a593Smuzhiyun goto err_ret;
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun /* PHY_CTRL3 : disable all timers and remaining interrupts */
1127*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_PHY_CTRL3,
1128*4882a593Smuzhiyun DAR_PHY_CTRL3_ASM_MSK | DAR_PHY_CTRL3_PB_ERR_MSK |
1129*4882a593Smuzhiyun DAR_PHY_CTRL3_WAKE_MSK);
1130*4882a593Smuzhiyun if (ret)
1131*4882a593Smuzhiyun goto err_ret;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /* SRC_CTRL : enable Acknowledge Frame Pending and
1134*4882a593Smuzhiyun * Source Address Matching Enable
1135*4882a593Smuzhiyun */
1136*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_SRC_CTRL,
1137*4882a593Smuzhiyun DAR_SRC_CTRL_ACK_FRM_PND |
1138*4882a593Smuzhiyun (DAR_SRC_CTRL_INDEX << DAR_SRC_CTRL_INDEX_SHIFT));
1139*4882a593Smuzhiyun if (ret)
1140*4882a593Smuzhiyun goto err_ret;
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun /* RX_FRAME_FILTER */
1143*4882a593Smuzhiyun /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets */
1144*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER,
1145*4882a593Smuzhiyun IAR_RX_FRAME_FLT_FRM_VER |
1146*4882a593Smuzhiyun IAR_RX_FRAME_FLT_BEACON_FT |
1147*4882a593Smuzhiyun IAR_RX_FRAME_FLT_DATA_FT |
1148*4882a593Smuzhiyun IAR_RX_FRAME_FLT_CMD_FT);
1149*4882a593Smuzhiyun if (ret)
1150*4882a593Smuzhiyun goto err_ret;
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun dev_info(printdev(lp), "MCR20A DAR overwrites version: 0x%02x\n",
1153*4882a593Smuzhiyun MCR20A_OVERWRITE_VERSION);
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun /* Overwrites direct registers */
1156*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_OVERWRITE_VER,
1157*4882a593Smuzhiyun MCR20A_OVERWRITE_VERSION);
1158*4882a593Smuzhiyun if (ret)
1159*4882a593Smuzhiyun goto err_ret;
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun /* Overwrites indirect registers */
1162*4882a593Smuzhiyun ret = regmap_multi_reg_write(lp->regmap_iar, mar20a_iar_overwrites,
1163*4882a593Smuzhiyun ARRAY_SIZE(mar20a_iar_overwrites));
1164*4882a593Smuzhiyun if (ret)
1165*4882a593Smuzhiyun goto err_ret;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun /* Clear HW indirect queue */
1168*4882a593Smuzhiyun dev_dbg(printdev(lp), "clear HW indirect queue\n");
1169*4882a593Smuzhiyun for (index = 0; index < MCR20A_PHY_INDIRECT_QUEUE_SIZE; index++) {
1170*4882a593Smuzhiyun phy_reg = (u8)(((index & DAR_SRC_CTRL_INDEX) <<
1171*4882a593Smuzhiyun DAR_SRC_CTRL_INDEX_SHIFT)
1172*4882a593Smuzhiyun | (DAR_SRC_CTRL_SRCADDR_EN)
1173*4882a593Smuzhiyun | (DAR_SRC_CTRL_INDEX_DISABLE));
1174*4882a593Smuzhiyun ret = regmap_write(lp->regmap_dar, DAR_SRC_CTRL, phy_reg);
1175*4882a593Smuzhiyun if (ret)
1176*4882a593Smuzhiyun goto err_ret;
1177*4882a593Smuzhiyun phy_reg = 0;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun /* Assign HW Indirect hash table to PAN0 */
1181*4882a593Smuzhiyun ret = regmap_read(lp->regmap_iar, IAR_DUAL_PAN_CTRL, &phy_reg);
1182*4882a593Smuzhiyun if (ret)
1183*4882a593Smuzhiyun goto err_ret;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun /* Clear current lvl */
1186*4882a593Smuzhiyun phy_reg &= ~IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun /* Set new lvl */
1189*4882a593Smuzhiyun phy_reg |= MCR20A_PHY_INDIRECT_QUEUE_SIZE <<
1190*4882a593Smuzhiyun IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_SHIFT;
1191*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_DUAL_PAN_CTRL, phy_reg);
1192*4882a593Smuzhiyun if (ret)
1193*4882a593Smuzhiyun goto err_ret;
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun /* Set CCA threshold to -75 dBm */
1196*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_CCA1_THRESH, 0x4B);
1197*4882a593Smuzhiyun if (ret)
1198*4882a593Smuzhiyun goto err_ret;
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun /* Set prescaller to obtain 1 symbol (16us) timebase */
1201*4882a593Smuzhiyun ret = regmap_write(lp->regmap_iar, IAR_TMR_PRESCALE, 0x05);
1202*4882a593Smuzhiyun if (ret)
1203*4882a593Smuzhiyun goto err_ret;
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun /* Enable autodoze mode. */
1206*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_PWR_MODES,
1207*4882a593Smuzhiyun DAR_PWR_MODES_AUTODOZE,
1208*4882a593Smuzhiyun DAR_PWR_MODES_AUTODOZE);
1209*4882a593Smuzhiyun if (ret)
1210*4882a593Smuzhiyun goto err_ret;
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun /* Disable clk_out */
1213*4882a593Smuzhiyun ret = regmap_update_bits(lp->regmap_dar, DAR_CLK_OUT_CTRL,
1214*4882a593Smuzhiyun DAR_CLK_OUT_CTRL_EN, 0x0);
1215*4882a593Smuzhiyun if (ret)
1216*4882a593Smuzhiyun goto err_ret;
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun return 0;
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun err_ret:
1221*4882a593Smuzhiyun return ret;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun static int
mcr20a_probe(struct spi_device * spi)1225*4882a593Smuzhiyun mcr20a_probe(struct spi_device *spi)
1226*4882a593Smuzhiyun {
1227*4882a593Smuzhiyun struct ieee802154_hw *hw;
1228*4882a593Smuzhiyun struct mcr20a_local *lp;
1229*4882a593Smuzhiyun struct gpio_desc *rst_b;
1230*4882a593Smuzhiyun int irq_type;
1231*4882a593Smuzhiyun int ret = -ENOMEM;
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun dev_dbg(&spi->dev, "%s\n", __func__);
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun if (!spi->irq) {
1236*4882a593Smuzhiyun dev_err(&spi->dev, "no IRQ specified\n");
1237*4882a593Smuzhiyun return -EINVAL;
1238*4882a593Smuzhiyun }
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun rst_b = devm_gpiod_get(&spi->dev, "rst_b", GPIOD_OUT_HIGH);
1241*4882a593Smuzhiyun if (IS_ERR(rst_b)) {
1242*4882a593Smuzhiyun ret = PTR_ERR(rst_b);
1243*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
1244*4882a593Smuzhiyun dev_err(&spi->dev, "Failed to get 'rst_b' gpio: %d", ret);
1245*4882a593Smuzhiyun return ret;
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun /* reset mcr20a */
1249*4882a593Smuzhiyun usleep_range(10, 20);
1250*4882a593Smuzhiyun gpiod_set_value_cansleep(rst_b, 1);
1251*4882a593Smuzhiyun usleep_range(10, 20);
1252*4882a593Smuzhiyun gpiod_set_value_cansleep(rst_b, 0);
1253*4882a593Smuzhiyun usleep_range(120, 240);
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun /* allocate ieee802154_hw and private data */
1256*4882a593Smuzhiyun hw = ieee802154_alloc_hw(sizeof(*lp), &mcr20a_hw_ops);
1257*4882a593Smuzhiyun if (!hw) {
1258*4882a593Smuzhiyun dev_crit(&spi->dev, "ieee802154_alloc_hw failed\n");
1259*4882a593Smuzhiyun return ret;
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun
1262*4882a593Smuzhiyun /* init mcr20a local data */
1263*4882a593Smuzhiyun lp = hw->priv;
1264*4882a593Smuzhiyun lp->hw = hw;
1265*4882a593Smuzhiyun lp->spi = spi;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun /* init ieee802154_hw */
1268*4882a593Smuzhiyun hw->parent = &spi->dev;
1269*4882a593Smuzhiyun ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun /* init buf */
1272*4882a593Smuzhiyun lp->buf = devm_kzalloc(&spi->dev, SPI_COMMAND_BUFFER, GFP_KERNEL);
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun if (!lp->buf) {
1275*4882a593Smuzhiyun ret = -ENOMEM;
1276*4882a593Smuzhiyun goto free_dev;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun mcr20a_setup_tx_spi_messages(lp);
1280*4882a593Smuzhiyun mcr20a_setup_rx_spi_messages(lp);
1281*4882a593Smuzhiyun mcr20a_setup_irq_spi_messages(lp);
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun /* setup regmap */
1284*4882a593Smuzhiyun lp->regmap_dar = devm_regmap_init_spi(spi, &mcr20a_dar_regmap);
1285*4882a593Smuzhiyun if (IS_ERR(lp->regmap_dar)) {
1286*4882a593Smuzhiyun ret = PTR_ERR(lp->regmap_dar);
1287*4882a593Smuzhiyun dev_err(&spi->dev, "Failed to allocate dar map: %d\n",
1288*4882a593Smuzhiyun ret);
1289*4882a593Smuzhiyun goto free_dev;
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun lp->regmap_iar = devm_regmap_init_spi(spi, &mcr20a_iar_regmap);
1293*4882a593Smuzhiyun if (IS_ERR(lp->regmap_iar)) {
1294*4882a593Smuzhiyun ret = PTR_ERR(lp->regmap_iar);
1295*4882a593Smuzhiyun dev_err(&spi->dev, "Failed to allocate iar map: %d\n", ret);
1296*4882a593Smuzhiyun goto free_dev;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun mcr20a_hw_setup(lp);
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun spi_set_drvdata(spi, lp);
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun ret = mcr20a_phy_init(lp);
1304*4882a593Smuzhiyun if (ret < 0) {
1305*4882a593Smuzhiyun dev_crit(&spi->dev, "mcr20a_phy_init failed\n");
1306*4882a593Smuzhiyun goto free_dev;
1307*4882a593Smuzhiyun }
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun irq_type = irq_get_trigger_type(spi->irq);
1310*4882a593Smuzhiyun if (!irq_type)
1311*4882a593Smuzhiyun irq_type = IRQF_TRIGGER_FALLING;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun ret = devm_request_irq(&spi->dev, spi->irq, mcr20a_irq_isr,
1314*4882a593Smuzhiyun irq_type, dev_name(&spi->dev), lp);
1315*4882a593Smuzhiyun if (ret) {
1316*4882a593Smuzhiyun dev_err(&spi->dev, "could not request_irq for mcr20a\n");
1317*4882a593Smuzhiyun ret = -ENODEV;
1318*4882a593Smuzhiyun goto free_dev;
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun /* disable_irq by default and wait for starting hardware */
1322*4882a593Smuzhiyun disable_irq(spi->irq);
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun ret = ieee802154_register_hw(hw);
1325*4882a593Smuzhiyun if (ret) {
1326*4882a593Smuzhiyun dev_crit(&spi->dev, "ieee802154_register_hw failed\n");
1327*4882a593Smuzhiyun goto free_dev;
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun return ret;
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun free_dev:
1333*4882a593Smuzhiyun ieee802154_free_hw(lp->hw);
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun return ret;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun
mcr20a_remove(struct spi_device * spi)1338*4882a593Smuzhiyun static int mcr20a_remove(struct spi_device *spi)
1339*4882a593Smuzhiyun {
1340*4882a593Smuzhiyun struct mcr20a_local *lp = spi_get_drvdata(spi);
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun dev_dbg(&spi->dev, "%s\n", __func__);
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun ieee802154_unregister_hw(lp->hw);
1345*4882a593Smuzhiyun ieee802154_free_hw(lp->hw);
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun return 0;
1348*4882a593Smuzhiyun }
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun static const struct of_device_id mcr20a_of_match[] = {
1351*4882a593Smuzhiyun { .compatible = "nxp,mcr20a", },
1352*4882a593Smuzhiyun { },
1353*4882a593Smuzhiyun };
1354*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, mcr20a_of_match);
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun static const struct spi_device_id mcr20a_device_id[] = {
1357*4882a593Smuzhiyun { .name = "mcr20a", },
1358*4882a593Smuzhiyun { },
1359*4882a593Smuzhiyun };
1360*4882a593Smuzhiyun MODULE_DEVICE_TABLE(spi, mcr20a_device_id);
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun static struct spi_driver mcr20a_driver = {
1363*4882a593Smuzhiyun .id_table = mcr20a_device_id,
1364*4882a593Smuzhiyun .driver = {
1365*4882a593Smuzhiyun .of_match_table = of_match_ptr(mcr20a_of_match),
1366*4882a593Smuzhiyun .name = "mcr20a",
1367*4882a593Smuzhiyun },
1368*4882a593Smuzhiyun .probe = mcr20a_probe,
1369*4882a593Smuzhiyun .remove = mcr20a_remove,
1370*4882a593Smuzhiyun };
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun module_spi_driver(mcr20a_driver);
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun MODULE_DESCRIPTION("MCR20A Transceiver Driver");
1375*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1376*4882a593Smuzhiyun MODULE_AUTHOR("Xue Liu <liuxuenetmail@gmail>");
1377