Commit | Line | Data |
---|---|---|
7b8e19b6 | 1 | /* |
2 | * AT86RF230/RF231 driver | |
3 | * | |
4 | * Copyright (C) 2009-2012 Siemens AG | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
7b8e19b6 | 15 | * Written by: |
16 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | |
17 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | |
01ebd60b | 18 | * Alexander Aring <aar@pengutronix.de> |
7b8e19b6 | 19 | */ |
20 | #include <linux/kernel.h> | |
21 | #include <linux/module.h> | |
eb3b435e | 22 | #include <linux/hrtimer.h> |
dce481e6 | 23 | #include <linux/jiffies.h> |
7b8e19b6 | 24 | #include <linux/interrupt.h> |
4af619ae | 25 | #include <linux/irq.h> |
7b8e19b6 | 26 | #include <linux/gpio.h> |
27 | #include <linux/delay.h> | |
7b8e19b6 | 28 | #include <linux/spi/spi.h> |
29 | #include <linux/spi/at86rf230.h> | |
f76014f7 | 30 | #include <linux/regmap.h> |
7b8e19b6 | 31 | #include <linux/skbuff.h> |
fa2d3e94 | 32 | #include <linux/of_gpio.h> |
4ca24aca | 33 | #include <linux/ieee802154.h> |
493bc90a | 34 | #include <linux/debugfs.h> |
7b8e19b6 | 35 | |
36 | #include <net/mac802154.h> | |
5ad60d36 | 37 | #include <net/cfg802154.h> |
7b8e19b6 | 38 | |
7490b008 AA |
39 | #include "at86rf230.h" |
40 | ||
a53d1f7c AA |
41 | struct at86rf230_local; |
42 | /* at86rf2xx chip depend data. | |
43 | * All timings are in us. | |
44 | */ | |
45 | struct at86rf2xx_chip_data { | |
7a4ef918 | 46 | u16 t_sleep_cycle; |
984e0c68 | 47 | u16 t_channel_switch; |
09e536cd | 48 | u16 t_reset_to_off; |
2e0571c0 AA |
49 | u16 t_off_to_aack; |
50 | u16 t_off_to_tx_on; | |
e6f7ed9d AA |
51 | u16 t_off_to_sleep; |
52 | u16 t_sleep_to_off; | |
1d15d6b5 AA |
53 | u16 t_frame; |
54 | u16 t_p_ack; | |
a53d1f7c AA |
55 | int rssi_base_val; |
56 | ||
e37d2ec8 | 57 | int (*set_channel)(struct at86rf230_local *, u8, u8); |
6f4da3f8 | 58 | int (*set_txpower)(struct at86rf230_local *, s32); |
a53d1f7c AA |
59 | }; |
60 | ||
ba6d2239 AA |
61 | #define AT86RF2XX_MAX_BUF (127 + 3) |
62 | /* tx retries to access the TX_ON state | |
63 | * if it's above then force change will be started. | |
64 | * | |
65 | * We assume the max_frame_retries (7) value of 802.15.4 here. | |
66 | */ | |
67 | #define AT86RF2XX_MAX_TX_RETRIES 7 | |
dce481e6 AA |
68 | /* We use the recommended 5 minutes timeout to recalibrate */ |
69 | #define AT86RF2XX_CAL_LOOP_TIMEOUT (5 * 60 * HZ) | |
7b8e19b6 | 70 | |
1d15d6b5 AA |
71 | struct at86rf230_state_change { |
72 | struct at86rf230_local *lp; | |
cca990c8 | 73 | int irq; |
7b8e19b6 | 74 | |
eb3b435e | 75 | struct hrtimer timer; |
1d15d6b5 AA |
76 | struct spi_message msg; |
77 | struct spi_transfer trx; | |
78 | u8 buf[AT86RF2XX_MAX_BUF]; | |
79 | ||
80 | void (*complete)(void *context); | |
81 | u8 from_state; | |
82 | u8 to_state; | |
97fed795 AA |
83 | |
84 | bool irq_enable; | |
1d15d6b5 AA |
85 | }; |
86 | ||
493bc90a AA |
87 | struct at86rf230_trac { |
88 | u64 success; | |
89 | u64 success_data_pending; | |
90 | u64 success_wait_for_ack; | |
91 | u64 channel_access_failure; | |
92 | u64 no_ack; | |
93 | u64 invalid; | |
94 | }; | |
95 | ||
1d15d6b5 AA |
96 | struct at86rf230_local { |
97 | struct spi_device *spi; | |
7b8e19b6 | 98 | |
5a504397 | 99 | struct ieee802154_hw *hw; |
1d15d6b5 | 100 | struct at86rf2xx_chip_data *data; |
f76014f7 | 101 | struct regmap *regmap; |
d2c8bf51 | 102 | int slp_tr; |
cbe62346 | 103 | bool sleep; |
7b8e19b6 | 104 | |
2e0571c0 AA |
105 | struct completion state_complete; |
106 | struct at86rf230_state_change state; | |
107 | ||
1d15d6b5 | 108 | struct at86rf230_state_change irq; |
6ca00197 | 109 | |
dce481e6 | 110 | unsigned long cal_timeout; |
1d15d6b5 | 111 | bool is_tx; |
85009203 | 112 | bool is_tx_from_off; |
ba6d2239 | 113 | u8 tx_retry; |
1d15d6b5 AA |
114 | struct sk_buff *tx_skb; |
115 | struct at86rf230_state_change tx; | |
493bc90a AA |
116 | |
117 | struct at86rf230_trac trac; | |
7b8e19b6 | 118 | }; |
119 | ||
f76014f7 AA |
120 | #define AT86RF2XX_NUMREGS 0x3F |
121 | ||
97fed795 | 122 | static void |
1d15d6b5 AA |
123 | at86rf230_async_state_change(struct at86rf230_local *lp, |
124 | struct at86rf230_state_change *ctx, | |
97fed795 AA |
125 | const u8 state, void (*complete)(void *context), |
126 | const bool irq_enable); | |
1d15d6b5 | 127 | |
cbe62346 AA |
128 | static inline void |
129 | at86rf230_sleep(struct at86rf230_local *lp) | |
130 | { | |
131 | if (gpio_is_valid(lp->slp_tr)) { | |
132 | gpio_set_value(lp->slp_tr, 1); | |
133 | usleep_range(lp->data->t_off_to_sleep, | |
134 | lp->data->t_off_to_sleep + 10); | |
135 | lp->sleep = true; | |
136 | } | |
137 | } | |
138 | ||
139 | static inline void | |
140 | at86rf230_awake(struct at86rf230_local *lp) | |
141 | { | |
142 | if (gpio_is_valid(lp->slp_tr)) { | |
143 | gpio_set_value(lp->slp_tr, 0); | |
144 | usleep_range(lp->data->t_sleep_to_off, | |
145 | lp->data->t_sleep_to_off + 100); | |
146 | lp->sleep = false; | |
147 | } | |
148 | } | |
149 | ||
f76014f7 AA |
150 | static inline int |
151 | __at86rf230_write(struct at86rf230_local *lp, | |
152 | unsigned int addr, unsigned int data) | |
153 | { | |
cbe62346 AA |
154 | bool sleep = lp->sleep; |
155 | int ret; | |
156 | ||
157 | /* awake for register setting if sleep */ | |
158 | if (sleep) | |
159 | at86rf230_awake(lp); | |
160 | ||
161 | ret = regmap_write(lp->regmap, addr, data); | |
162 | ||
163 | /* sleep again if was sleeping */ | |
164 | if (sleep) | |
165 | at86rf230_sleep(lp); | |
166 | ||
167 | return ret; | |
f76014f7 AA |
168 | } |
169 | ||
170 | static inline int | |
171 | __at86rf230_read(struct at86rf230_local *lp, | |
172 | unsigned int addr, unsigned int *data) | |
173 | { | |
cbe62346 AA |
174 | bool sleep = lp->sleep; |
175 | int ret; | |
176 | ||
177 | /* awake for register setting if sleep */ | |
178 | if (sleep) | |
179 | at86rf230_awake(lp); | |
180 | ||
181 | ret = regmap_read(lp->regmap, addr, data); | |
182 | ||
183 | /* sleep again if was sleeping */ | |
184 | if (sleep) | |
185 | at86rf230_sleep(lp); | |
186 | ||
187 | return ret; | |
f76014f7 AA |
188 | } |
189 | ||
190 | static inline int | |
191 | at86rf230_read_subreg(struct at86rf230_local *lp, | |
192 | unsigned int addr, unsigned int mask, | |
193 | unsigned int shift, unsigned int *data) | |
194 | { | |
195 | int rc; | |
196 | ||
197 | rc = __at86rf230_read(lp, addr, data); | |
d907c4f0 | 198 | if (!rc) |
f76014f7 AA |
199 | *data = (*data & mask) >> shift; |
200 | ||
201 | return rc; | |
202 | } | |
203 | ||
204 | static inline int | |
205 | at86rf230_write_subreg(struct at86rf230_local *lp, | |
206 | unsigned int addr, unsigned int mask, | |
207 | unsigned int shift, unsigned int data) | |
208 | { | |
cbe62346 AA |
209 | bool sleep = lp->sleep; |
210 | int ret; | |
211 | ||
212 | /* awake for register setting if sleep */ | |
213 | if (sleep) | |
214 | at86rf230_awake(lp); | |
215 | ||
216 | ret = regmap_update_bits(lp->regmap, addr, mask, data << shift); | |
217 | ||
218 | /* sleep again if was sleeping */ | |
219 | if (sleep) | |
220 | at86rf230_sleep(lp); | |
221 | ||
222 | return ret; | |
f76014f7 AA |
223 | } |
224 | ||
d2c8bf51 AA |
225 | static inline void |
226 | at86rf230_slp_tr_rising_edge(struct at86rf230_local *lp) | |
227 | { | |
228 | gpio_set_value(lp->slp_tr, 1); | |
229 | udelay(1); | |
230 | gpio_set_value(lp->slp_tr, 0); | |
231 | } | |
232 | ||
f76014f7 AA |
233 | static bool |
234 | at86rf230_reg_writeable(struct device *dev, unsigned int reg) | |
235 | { | |
236 | switch (reg) { | |
237 | case RG_TRX_STATE: | |
238 | case RG_TRX_CTRL_0: | |
239 | case RG_TRX_CTRL_1: | |
240 | case RG_PHY_TX_PWR: | |
241 | case RG_PHY_ED_LEVEL: | |
242 | case RG_PHY_CC_CCA: | |
243 | case RG_CCA_THRES: | |
244 | case RG_RX_CTRL: | |
245 | case RG_SFD_VALUE: | |
246 | case RG_TRX_CTRL_2: | |
247 | case RG_ANT_DIV: | |
248 | case RG_IRQ_MASK: | |
249 | case RG_VREG_CTRL: | |
250 | case RG_BATMON: | |
251 | case RG_XOSC_CTRL: | |
252 | case RG_RX_SYN: | |
253 | case RG_XAH_CTRL_1: | |
254 | case RG_FTN_CTRL: | |
255 | case RG_PLL_CF: | |
256 | case RG_PLL_DCU: | |
257 | case RG_SHORT_ADDR_0: | |
258 | case RG_SHORT_ADDR_1: | |
259 | case RG_PAN_ID_0: | |
260 | case RG_PAN_ID_1: | |
261 | case RG_IEEE_ADDR_0: | |
262 | case RG_IEEE_ADDR_1: | |
263 | case RG_IEEE_ADDR_2: | |
264 | case RG_IEEE_ADDR_3: | |
265 | case RG_IEEE_ADDR_4: | |
266 | case RG_IEEE_ADDR_5: | |
267 | case RG_IEEE_ADDR_6: | |
268 | case RG_IEEE_ADDR_7: | |
269 | case RG_XAH_CTRL_0: | |
270 | case RG_CSMA_SEED_0: | |
271 | case RG_CSMA_SEED_1: | |
272 | case RG_CSMA_BE: | |
273 | return true; | |
274 | default: | |
275 | return false; | |
276 | } | |
277 | } | |
278 | ||
279 | static bool | |
280 | at86rf230_reg_readable(struct device *dev, unsigned int reg) | |
281 | { | |
282 | bool rc; | |
283 | ||
284 | /* all writeable are also readable */ | |
285 | rc = at86rf230_reg_writeable(dev, reg); | |
286 | if (rc) | |
287 | return rc; | |
288 | ||
289 | /* readonly regs */ | |
290 | switch (reg) { | |
291 | case RG_TRX_STATUS: | |
292 | case RG_PHY_RSSI: | |
293 | case RG_IRQ_STATUS: | |
294 | case RG_PART_NUM: | |
295 | case RG_VERSION_NUM: | |
296 | case RG_MAN_ID_1: | |
297 | case RG_MAN_ID_0: | |
298 | return true; | |
299 | default: | |
300 | return false; | |
301 | } | |
302 | } | |
303 | ||
304 | static bool | |
305 | at86rf230_reg_volatile(struct device *dev, unsigned int reg) | |
306 | { | |
307 | /* can be changed during runtime */ | |
308 | switch (reg) { | |
309 | case RG_TRX_STATUS: | |
310 | case RG_TRX_STATE: | |
311 | case RG_PHY_RSSI: | |
312 | case RG_PHY_ED_LEVEL: | |
313 | case RG_IRQ_STATUS: | |
314 | case RG_VREG_CTRL: | |
51b3b2cf AA |
315 | case RG_PLL_CF: |
316 | case RG_PLL_DCU: | |
f76014f7 AA |
317 | return true; |
318 | default: | |
319 | return false; | |
320 | } | |
321 | } | |
322 | ||
323 | static bool | |
324 | at86rf230_reg_precious(struct device *dev, unsigned int reg) | |
325 | { | |
326 | /* don't clear irq line on read */ | |
327 | switch (reg) { | |
328 | case RG_IRQ_STATUS: | |
329 | return true; | |
330 | default: | |
331 | return false; | |
332 | } | |
333 | } | |
334 | ||
889ee2c7 | 335 | static const struct regmap_config at86rf230_regmap_spi_config = { |
f76014f7 AA |
336 | .reg_bits = 8, |
337 | .val_bits = 8, | |
338 | .write_flag_mask = CMD_REG | CMD_WRITE, | |
339 | .read_flag_mask = CMD_REG, | |
340 | .cache_type = REGCACHE_RBTREE, | |
341 | .max_register = AT86RF2XX_NUMREGS, | |
342 | .writeable_reg = at86rf230_reg_writeable, | |
343 | .readable_reg = at86rf230_reg_readable, | |
344 | .volatile_reg = at86rf230_reg_volatile, | |
345 | .precious_reg = at86rf230_reg_precious, | |
346 | }; | |
347 | ||
1d15d6b5 AA |
348 | static void |
349 | at86rf230_async_error_recover(void *context) | |
350 | { | |
351 | struct at86rf230_state_change *ctx = context; | |
352 | struct at86rf230_local *lp = ctx->lp; | |
353 | ||
a7a484bf | 354 | lp->is_tx = 0; |
97fed795 | 355 | at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false); |
955aee8b | 356 | ieee802154_wake_queue(lp->hw); |
1d15d6b5 AA |
357 | } |
358 | ||
fc50c6e3 | 359 | static inline void |
1d15d6b5 AA |
360 | at86rf230_async_error(struct at86rf230_local *lp, |
361 | struct at86rf230_state_change *ctx, int rc) | |
362 | { | |
363 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | |
364 | ||
365 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, | |
97fed795 | 366 | at86rf230_async_error_recover, false); |
1d15d6b5 AA |
367 | } |
368 | ||
369 | /* Generic function to get some register value in async mode */ | |
97fed795 | 370 | static void |
1d15d6b5 AA |
371 | at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, |
372 | struct at86rf230_state_change *ctx, | |
97fed795 AA |
373 | void (*complete)(void *context), |
374 | const bool irq_enable) | |
7b8e19b6 | 375 | { |
97fed795 AA |
376 | int rc; |
377 | ||
1d15d6b5 AA |
378 | u8 *tx_buf = ctx->buf; |
379 | ||
380 | tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; | |
1d15d6b5 | 381 | ctx->msg.complete = complete; |
97fed795 AA |
382 | ctx->irq_enable = irq_enable; |
383 | rc = spi_async(lp->spi, &ctx->msg); | |
384 | if (rc) { | |
385 | if (irq_enable) | |
cca990c8 | 386 | enable_irq(ctx->irq); |
97fed795 AA |
387 | |
388 | at86rf230_async_error(lp, ctx, rc); | |
389 | } | |
1d15d6b5 AA |
390 | } |
391 | ||
392 | static void | |
393 | at86rf230_async_state_assert(void *context) | |
394 | { | |
395 | struct at86rf230_state_change *ctx = context; | |
396 | struct at86rf230_local *lp = ctx->lp; | |
397 | const u8 *buf = ctx->buf; | |
4748e86e | 398 | const u8 trx_state = buf[1] & TRX_STATE_MASK; |
1d15d6b5 AA |
399 | |
400 | /* Assert state change */ | |
401 | if (trx_state != ctx->to_state) { | |
402 | /* Special handling if transceiver state is in | |
403 | * STATE_BUSY_RX_AACK and a SHR was detected. | |
404 | */ | |
405 | if (trx_state == STATE_BUSY_RX_AACK) { | |
406 | /* Undocumented race condition. If we send a state | |
407 | * change to STATE_RX_AACK_ON the transceiver could | |
408 | * change his state automatically to STATE_BUSY_RX_AACK | |
409 | * if a SHR was detected. This is not an error, but we | |
410 | * can't assert this. | |
411 | */ | |
412 | if (ctx->to_state == STATE_RX_AACK_ON) | |
413 | goto done; | |
414 | ||
415 | /* If we change to STATE_TX_ON without forcing and | |
416 | * transceiver state is STATE_BUSY_RX_AACK, we wait | |
417 | * 'tFrame + tPAck' receiving time. In this time the | |
418 | * PDU should be received. If the transceiver is still | |
419 | * in STATE_BUSY_RX_AACK, we run a force state change | |
420 | * to STATE_TX_ON. This is a timeout handling, if the | |
421 | * transceiver stucks in STATE_BUSY_RX_AACK. | |
ba6d2239 AA |
422 | * |
423 | * Additional we do several retries to try to get into | |
424 | * TX_ON state without forcing. If the retries are | |
425 | * higher or equal than AT86RF2XX_MAX_TX_RETRIES we | |
426 | * will do a force change. | |
1d15d6b5 | 427 | */ |
dce481e6 AA |
428 | if (ctx->to_state == STATE_TX_ON || |
429 | ctx->to_state == STATE_TRX_OFF) { | |
430 | u8 state = ctx->to_state; | |
ba6d2239 AA |
431 | |
432 | if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) | |
ed4a26b0 | 433 | state = STATE_FORCE_TRX_OFF; |
ba6d2239 AA |
434 | lp->tx_retry++; |
435 | ||
436 | at86rf230_async_state_change(lp, ctx, state, | |
97fed795 AA |
437 | ctx->complete, |
438 | ctx->irq_enable); | |
1d15d6b5 AA |
439 | return; |
440 | } | |
441 | } | |
442 | ||
1d15d6b5 AA |
443 | dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n", |
444 | ctx->from_state, ctx->to_state, trx_state); | |
445 | } | |
446 | ||
447 | done: | |
448 | if (ctx->complete) | |
449 | ctx->complete(context); | |
450 | } | |
451 | ||
eb3b435e AA |
452 | static enum hrtimer_restart at86rf230_async_state_timer(struct hrtimer *timer) |
453 | { | |
454 | struct at86rf230_state_change *ctx = | |
455 | container_of(timer, struct at86rf230_state_change, timer); | |
456 | struct at86rf230_local *lp = ctx->lp; | |
457 | ||
458 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | |
459 | at86rf230_async_state_assert, | |
460 | ctx->irq_enable); | |
461 | ||
462 | return HRTIMER_NORESTART; | |
463 | } | |
464 | ||
1d15d6b5 AA |
465 | /* Do state change timing delay. */ |
466 | static void | |
467 | at86rf230_async_state_delay(void *context) | |
468 | { | |
469 | struct at86rf230_state_change *ctx = context; | |
470 | struct at86rf230_local *lp = ctx->lp; | |
471 | struct at86rf2xx_chip_data *c = lp->data; | |
472 | bool force = false; | |
eb3b435e | 473 | ktime_t tim; |
1d15d6b5 AA |
474 | |
475 | /* The force state changes are will show as normal states in the | |
476 | * state status subregister. We change the to_state to the | |
477 | * corresponding one and remember if it was a force change, this | |
478 | * differs if we do a state change from STATE_BUSY_RX_AACK. | |
479 | */ | |
480 | switch (ctx->to_state) { | |
481 | case STATE_FORCE_TX_ON: | |
482 | ctx->to_state = STATE_TX_ON; | |
483 | force = true; | |
484 | break; | |
485 | case STATE_FORCE_TRX_OFF: | |
486 | ctx->to_state = STATE_TRX_OFF; | |
487 | force = true; | |
488 | break; | |
489 | default: | |
490 | break; | |
491 | } | |
492 | ||
493 | switch (ctx->from_state) { | |
2e0571c0 AA |
494 | case STATE_TRX_OFF: |
495 | switch (ctx->to_state) { | |
496 | case STATE_RX_AACK_ON: | |
eb3b435e | 497 | tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC); |
2ad33244 AA |
498 | /* state change from TRX_OFF to RX_AACK_ON to do a |
499 | * calibration, we need to reset the timeout for the | |
500 | * next one. | |
501 | */ | |
502 | lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; | |
2e0571c0 | 503 | goto change; |
3b951ca7 | 504 | case STATE_TX_ARET_ON: |
2e0571c0 | 505 | case STATE_TX_ON: |
eb3b435e | 506 | tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); |
3b951ca7 AA |
507 | /* state change from TRX_OFF to TX_ON or ARET_ON to do |
508 | * a calibration, we need to reset the timeout for the | |
dce481e6 AA |
509 | * next one. |
510 | */ | |
511 | lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; | |
2e0571c0 AA |
512 | goto change; |
513 | default: | |
514 | break; | |
515 | } | |
516 | break; | |
1d15d6b5 AA |
517 | case STATE_BUSY_RX_AACK: |
518 | switch (ctx->to_state) { | |
dce481e6 | 519 | case STATE_TRX_OFF: |
1d15d6b5 AA |
520 | case STATE_TX_ON: |
521 | /* Wait for worst case receiving time if we | |
522 | * didn't make a force change from BUSY_RX_AACK | |
dce481e6 | 523 | * to TX_ON or TRX_OFF. |
1d15d6b5 AA |
524 | */ |
525 | if (!force) { | |
eb3b435e AA |
526 | tim = ktime_set(0, (c->t_frame + c->t_p_ack) * |
527 | NSEC_PER_USEC); | |
1d15d6b5 AA |
528 | goto change; |
529 | } | |
530 | break; | |
531 | default: | |
532 | break; | |
533 | } | |
534 | break; | |
09e536cd AA |
535 | /* Default value, means RESET state */ |
536 | case STATE_P_ON: | |
537 | switch (ctx->to_state) { | |
538 | case STATE_TRX_OFF: | |
eb3b435e | 539 | tim = ktime_set(0, c->t_reset_to_off * NSEC_PER_USEC); |
09e536cd AA |
540 | goto change; |
541 | default: | |
542 | break; | |
543 | } | |
544 | break; | |
1d15d6b5 AA |
545 | default: |
546 | break; | |
547 | } | |
548 | ||
549 | /* Default delay is 1us in the most cases */ | |
8b44f0dd AA |
550 | udelay(1); |
551 | at86rf230_async_state_timer(&ctx->timer); | |
552 | return; | |
1d15d6b5 AA |
553 | |
554 | change: | |
eb3b435e | 555 | hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL); |
1d15d6b5 AA |
556 | } |
557 | ||
558 | static void | |
559 | at86rf230_async_state_change_start(void *context) | |
560 | { | |
561 | struct at86rf230_state_change *ctx = context; | |
562 | struct at86rf230_local *lp = ctx->lp; | |
563 | u8 *buf = ctx->buf; | |
4748e86e | 564 | const u8 trx_state = buf[1] & TRX_STATE_MASK; |
1d15d6b5 AA |
565 | int rc; |
566 | ||
567 | /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ | |
568 | if (trx_state == STATE_TRANSITION_IN_PROGRESS) { | |
569 | udelay(1); | |
97fed795 AA |
570 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
571 | at86rf230_async_state_change_start, | |
572 | ctx->irq_enable); | |
1d15d6b5 AA |
573 | return; |
574 | } | |
575 | ||
576 | /* Check if we already are in the state which we change in */ | |
577 | if (trx_state == ctx->to_state) { | |
578 | if (ctx->complete) | |
579 | ctx->complete(context); | |
580 | return; | |
581 | } | |
582 | ||
583 | /* Set current state to the context of state change */ | |
584 | ctx->from_state = trx_state; | |
585 | ||
586 | /* Going into the next step for a state change which do a timing | |
587 | * relevant delay. | |
588 | */ | |
589 | buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; | |
590 | buf[1] = ctx->to_state; | |
1d15d6b5 AA |
591 | ctx->msg.complete = at86rf230_async_state_delay; |
592 | rc = spi_async(lp->spi, &ctx->msg); | |
97fed795 AA |
593 | if (rc) { |
594 | if (ctx->irq_enable) | |
cca990c8 | 595 | enable_irq(ctx->irq); |
97fed795 | 596 | |
4fef7d3b | 597 | at86rf230_async_error(lp, ctx, rc); |
97fed795 | 598 | } |
7b8e19b6 | 599 | } |
600 | ||
97fed795 | 601 | static void |
1d15d6b5 AA |
602 | at86rf230_async_state_change(struct at86rf230_local *lp, |
603 | struct at86rf230_state_change *ctx, | |
97fed795 AA |
604 | const u8 state, void (*complete)(void *context), |
605 | const bool irq_enable) | |
7b8e19b6 | 606 | { |
1d15d6b5 AA |
607 | /* Initialization for the state change context */ |
608 | ctx->to_state = state; | |
609 | ctx->complete = complete; | |
97fed795 AA |
610 | ctx->irq_enable = irq_enable; |
611 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | |
612 | at86rf230_async_state_change_start, | |
613 | irq_enable); | |
1d15d6b5 | 614 | } |
7b8e19b6 | 615 | |
2e0571c0 AA |
616 | static void |
617 | at86rf230_sync_state_change_complete(void *context) | |
618 | { | |
619 | struct at86rf230_state_change *ctx = context; | |
620 | struct at86rf230_local *lp = ctx->lp; | |
621 | ||
622 | complete(&lp->state_complete); | |
623 | } | |
624 | ||
625 | /* This function do a sync framework above the async state change. | |
626 | * Some callbacks of the IEEE 802.15.4 driver interface need to be | |
627 | * handled synchronously. | |
628 | */ | |
629 | static int | |
630 | at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state) | |
631 | { | |
3e544ef9 | 632 | unsigned long rc; |
2e0571c0 | 633 | |
97fed795 AA |
634 | at86rf230_async_state_change(lp, &lp->state, state, |
635 | at86rf230_sync_state_change_complete, | |
636 | false); | |
2e0571c0 AA |
637 | |
638 | rc = wait_for_completion_timeout(&lp->state_complete, | |
639 | msecs_to_jiffies(100)); | |
d06c2199 AA |
640 | if (!rc) { |
641 | at86rf230_async_error(lp, &lp->state, -ETIMEDOUT); | |
2e0571c0 | 642 | return -ETIMEDOUT; |
d06c2199 | 643 | } |
2e0571c0 AA |
644 | |
645 | return 0; | |
646 | } | |
647 | ||
1d15d6b5 AA |
648 | static void |
649 | at86rf230_tx_complete(void *context) | |
650 | { | |
651 | struct at86rf230_state_change *ctx = context; | |
652 | struct at86rf230_local *lp = ctx->lp; | |
653 | ||
cca990c8 | 654 | enable_irq(ctx->irq); |
955aee8b | 655 | |
fc0719e6 | 656 | ieee802154_xmit_complete(lp->hw, lp->tx_skb, false); |
1d15d6b5 AA |
657 | } |
658 | ||
659 | static void | |
660 | at86rf230_tx_on(void *context) | |
661 | { | |
662 | struct at86rf230_state_change *ctx = context; | |
663 | struct at86rf230_local *lp = ctx->lp; | |
1d15d6b5 | 664 | |
31fa7434 | 665 | at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, |
97fed795 | 666 | at86rf230_tx_complete, true); |
1d15d6b5 AA |
667 | } |
668 | ||
1d15d6b5 AA |
669 | static void |
670 | at86rf230_tx_trac_check(void *context) | |
671 | { | |
672 | struct at86rf230_state_change *ctx = context; | |
673 | struct at86rf230_local *lp = ctx->lp; | |
1d15d6b5 | 674 | |
493bc90a AA |
675 | if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) { |
676 | u8 trac = TRAC_MASK(ctx->buf[1]); | |
677 | ||
678 | switch (trac) { | |
679 | case TRAC_SUCCESS: | |
680 | lp->trac.success++; | |
681 | break; | |
682 | case TRAC_SUCCESS_DATA_PENDING: | |
683 | lp->trac.success_data_pending++; | |
684 | break; | |
685 | case TRAC_CHANNEL_ACCESS_FAILURE: | |
686 | lp->trac.channel_access_failure++; | |
687 | break; | |
688 | case TRAC_NO_ACK: | |
689 | lp->trac.no_ack++; | |
690 | break; | |
691 | case TRAC_INVALID: | |
692 | lp->trac.invalid++; | |
693 | break; | |
694 | default: | |
695 | WARN_ONCE(1, "received tx trac status %d\n", trac); | |
696 | break; | |
697 | } | |
698 | } | |
699 | ||
346ce4bb AA |
700 | at86rf230_async_state_change(lp, &lp->irq, STATE_TX_ON, |
701 | at86rf230_tx_on, true); | |
1d15d6b5 AA |
702 | } |
703 | ||
704 | static void | |
74de4c80 | 705 | at86rf230_rx_read_frame_complete(void *context) |
1d15d6b5 | 706 | { |
74de4c80 AA |
707 | struct at86rf230_state_change *ctx = context; |
708 | struct at86rf230_local *lp = ctx->lp; | |
1d15d6b5 | 709 | u8 rx_local_buf[AT86RF2XX_MAX_BUF]; |
31fa7434 | 710 | const u8 *buf = ctx->buf; |
74de4c80 AA |
711 | struct sk_buff *skb; |
712 | u8 len, lqi; | |
1d15d6b5 | 713 | |
74de4c80 AA |
714 | len = buf[1]; |
715 | if (!ieee802154_is_valid_psdu_len(len)) { | |
716 | dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); | |
717 | len = IEEE802154_MTU; | |
718 | } | |
719 | lqi = buf[2 + len]; | |
720 | ||
721 | memcpy(rx_local_buf, buf + 2, len); | |
263be332 | 722 | ctx->trx.len = 2; |
cca990c8 | 723 | enable_irq(ctx->irq); |
1d15d6b5 | 724 | |
61a22814 | 725 | skb = dev_alloc_skb(IEEE802154_MTU); |
1d15d6b5 AA |
726 | if (!skb) { |
727 | dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n"); | |
728 | return; | |
729 | } | |
730 | ||
731 | memcpy(skb_put(skb, len), rx_local_buf, len); | |
b89c3341 | 732 | ieee802154_rx_irqsafe(lp->hw, skb, lqi); |
1d15d6b5 | 733 | } |
7b8e19b6 | 734 | |
97fed795 | 735 | static void |
493bc90a | 736 | at86rf230_rx_trac_check(void *context) |
1d15d6b5 | 737 | { |
cca990c8 AA |
738 | struct at86rf230_state_change *ctx = context; |
739 | struct at86rf230_local *lp = ctx->lp; | |
31fa7434 | 740 | u8 *buf = ctx->buf; |
97fed795 AA |
741 | int rc; |
742 | ||
493bc90a AA |
743 | if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) { |
744 | u8 trac = TRAC_MASK(buf[1]); | |
745 | ||
746 | switch (trac) { | |
747 | case TRAC_SUCCESS: | |
748 | lp->trac.success++; | |
749 | break; | |
750 | case TRAC_SUCCESS_WAIT_FOR_ACK: | |
751 | lp->trac.success_wait_for_ack++; | |
752 | break; | |
753 | case TRAC_INVALID: | |
754 | lp->trac.invalid++; | |
755 | break; | |
756 | default: | |
757 | WARN_ONCE(1, "received rx trac status %d\n", trac); | |
758 | break; | |
759 | } | |
760 | } | |
761 | ||
7b8e19b6 | 762 | buf[0] = CMD_FB; |
31fa7434 AA |
763 | ctx->trx.len = AT86RF2XX_MAX_BUF; |
764 | ctx->msg.complete = at86rf230_rx_read_frame_complete; | |
765 | rc = spi_async(lp->spi, &ctx->msg); | |
97fed795 | 766 | if (rc) { |
263be332 | 767 | ctx->trx.len = 2; |
cca990c8 | 768 | enable_irq(ctx->irq); |
31fa7434 | 769 | at86rf230_async_error(lp, ctx, rc); |
97fed795 | 770 | } |
1d15d6b5 AA |
771 | } |
772 | ||
97fed795 | 773 | static void |
1d15d6b5 AA |
774 | at86rf230_irq_trx_end(struct at86rf230_local *lp) |
775 | { | |
1d15d6b5 AA |
776 | if (lp->is_tx) { |
777 | lp->is_tx = 0; | |
346ce4bb AA |
778 | at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, |
779 | at86rf230_tx_trac_check, true); | |
1d15d6b5 | 780 | } else { |
97fed795 AA |
781 | at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, |
782 | at86rf230_rx_trac_check, true); | |
1d15d6b5 AA |
783 | } |
784 | } | |
785 | ||
786 | static void | |
787 | at86rf230_irq_status(void *context) | |
788 | { | |
789 | struct at86rf230_state_change *ctx = context; | |
790 | struct at86rf230_local *lp = ctx->lp; | |
31fa7434 | 791 | const u8 *buf = ctx->buf; |
1d15d6b5 | 792 | const u8 irq = buf[1]; |
1d15d6b5 AA |
793 | |
794 | if (irq & IRQ_TRX_END) { | |
97fed795 | 795 | at86rf230_irq_trx_end(lp); |
1d15d6b5 | 796 | } else { |
cca990c8 | 797 | enable_irq(ctx->irq); |
1d15d6b5 AA |
798 | dev_err(&lp->spi->dev, "not supported irq %02x received\n", |
799 | irq); | |
800 | } | |
801 | } | |
802 | ||
803 | static irqreturn_t at86rf230_isr(int irq, void *data) | |
804 | { | |
805 | struct at86rf230_local *lp = data; | |
806 | struct at86rf230_state_change *ctx = &lp->irq; | |
807 | u8 *buf = ctx->buf; | |
808 | int rc; | |
809 | ||
90566363 | 810 | disable_irq_nosync(irq); |
1d15d6b5 AA |
811 | |
812 | buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG; | |
1d15d6b5 AA |
813 | ctx->msg.complete = at86rf230_irq_status; |
814 | rc = spi_async(lp->spi, &ctx->msg); | |
815 | if (rc) { | |
e9310211 | 816 | enable_irq(irq); |
1d15d6b5 AA |
817 | at86rf230_async_error(lp, ctx, rc); |
818 | return IRQ_NONE; | |
819 | } | |
820 | ||
821 | return IRQ_HANDLED; | |
822 | } | |
823 | ||
824 | static void | |
825 | at86rf230_write_frame_complete(void *context) | |
826 | { | |
827 | struct at86rf230_state_change *ctx = context; | |
828 | struct at86rf230_local *lp = ctx->lp; | |
829 | u8 *buf = ctx->buf; | |
830 | int rc; | |
831 | ||
1d15d6b5 | 832 | ctx->trx.len = 2; |
d2c8bf51 AA |
833 | |
834 | if (gpio_is_valid(lp->slp_tr)) { | |
835 | at86rf230_slp_tr_rising_edge(lp); | |
836 | } else { | |
837 | buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; | |
838 | buf[1] = STATE_BUSY_TX; | |
839 | ctx->msg.complete = NULL; | |
840 | rc = spi_async(lp->spi, &ctx->msg); | |
841 | if (rc) | |
842 | at86rf230_async_error(lp, ctx, rc); | |
843 | } | |
1d15d6b5 AA |
844 | } |
845 | ||
846 | static void | |
847 | at86rf230_write_frame(void *context) | |
848 | { | |
849 | struct at86rf230_state_change *ctx = context; | |
850 | struct at86rf230_local *lp = ctx->lp; | |
851 | struct sk_buff *skb = lp->tx_skb; | |
31fa7434 | 852 | u8 *buf = ctx->buf; |
1d15d6b5 AA |
853 | int rc; |
854 | ||
1d15d6b5 | 855 | lp->is_tx = 1; |
1d15d6b5 AA |
856 | |
857 | buf[0] = CMD_FB | CMD_WRITE; | |
858 | buf[1] = skb->len + 2; | |
859 | memcpy(buf + 2, skb->data, skb->len); | |
31fa7434 AA |
860 | ctx->trx.len = skb->len + 2; |
861 | ctx->msg.complete = at86rf230_write_frame_complete; | |
862 | rc = spi_async(lp->spi, &ctx->msg); | |
263be332 AA |
863 | if (rc) { |
864 | ctx->trx.len = 2; | |
1d15d6b5 | 865 | at86rf230_async_error(lp, ctx, rc); |
263be332 | 866 | } |
1d15d6b5 AA |
867 | } |
868 | ||
869 | static void | |
870 | at86rf230_xmit_tx_on(void *context) | |
871 | { | |
872 | struct at86rf230_state_change *ctx = context; | |
873 | struct at86rf230_local *lp = ctx->lp; | |
7b8e19b6 | 874 | |
97fed795 AA |
875 | at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, |
876 | at86rf230_write_frame, false); | |
1d15d6b5 AA |
877 | } |
878 | ||
dce481e6 AA |
879 | static void |
880 | at86rf230_xmit_start(void *context) | |
1d15d6b5 | 881 | { |
dce481e6 AA |
882 | struct at86rf230_state_change *ctx = context; |
883 | struct at86rf230_local *lp = ctx->lp; | |
7b8e19b6 | 884 | |
fc0719e6 AA |
885 | /* check if we change from off state */ |
886 | if (lp->is_tx_from_off) { | |
887 | lp->is_tx_from_off = false; | |
888 | at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, | |
889 | at86rf230_write_frame, | |
890 | false); | |
85009203 | 891 | } else { |
dce481e6 | 892 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, |
fc0719e6 AA |
893 | at86rf230_xmit_tx_on, |
894 | false); | |
85009203 | 895 | } |
dce481e6 AA |
896 | } |
897 | ||
898 | static int | |
899 | at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) | |
900 | { | |
901 | struct at86rf230_local *lp = hw->priv; | |
902 | struct at86rf230_state_change *ctx = &lp->tx; | |
7b8e19b6 | 903 | |
dce481e6 | 904 | lp->tx_skb = skb; |
ba6d2239 | 905 | lp->tx_retry = 0; |
dce481e6 AA |
906 | |
907 | /* After 5 minutes in PLL and the same frequency we run again the | |
908 | * calibration loops which is recommended by at86rf2xx datasheets. | |
909 | * | |
910 | * The calibration is initiate by a state change from TRX_OFF | |
911 | * to TX_ON, the lp->cal_timeout should be reinit by state_delay | |
912 | * function then to start in the next 5 minutes. | |
913 | */ | |
85009203 AA |
914 | if (time_is_before_jiffies(lp->cal_timeout)) { |
915 | lp->is_tx_from_off = true; | |
dce481e6 AA |
916 | at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF, |
917 | at86rf230_xmit_start, false); | |
85009203 | 918 | } else { |
dce481e6 | 919 | at86rf230_xmit_start(ctx); |
85009203 | 920 | } |
97fed795 | 921 | |
1d15d6b5 | 922 | return 0; |
7b8e19b6 | 923 | } |
924 | ||
925 | static int | |
5a504397 | 926 | at86rf230_ed(struct ieee802154_hw *hw, u8 *level) |
7b8e19b6 | 927 | { |
7b8e19b6 | 928 | BUG_ON(!level); |
929 | *level = 0xbe; | |
930 | return 0; | |
931 | } | |
932 | ||
7b8e19b6 | 933 | static int |
5a504397 | 934 | at86rf230_start(struct ieee802154_hw *hw) |
7b8e19b6 | 935 | { |
e6f7ed9d AA |
936 | struct at86rf230_local *lp = hw->priv; |
937 | ||
493bc90a AA |
938 | /* reset trac stats on start */ |
939 | if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) | |
940 | memset(&lp->trac, 0, sizeof(struct at86rf230_trac)); | |
941 | ||
cbe62346 | 942 | at86rf230_awake(lp); |
e6f7ed9d AA |
943 | enable_irq(lp->spi->irq); |
944 | ||
30811fa6 | 945 | return at86rf230_sync_state_change(lp, STATE_RX_AACK_ON); |
7b8e19b6 | 946 | } |
947 | ||
948 | static void | |
5a504397 | 949 | at86rf230_stop(struct ieee802154_hw *hw) |
7b8e19b6 | 950 | { |
e6f7ed9d | 951 | struct at86rf230_local *lp = hw->priv; |
74ed9d98 | 952 | u8 csma_seed[2]; |
e6f7ed9d | 953 | |
30811fa6 | 954 | at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF); |
e6f7ed9d AA |
955 | |
956 | disable_irq(lp->spi->irq); | |
74ed9d98 AA |
957 | |
958 | /* It's recommended to set random new csma_seeds before sleep state. | |
959 | * Makes only sense in the stop callback, not doing this inside of | |
960 | * at86rf230_sleep, this is also used when we don't transmit afterwards | |
961 | * when calling start callback again. | |
962 | */ | |
963 | get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed)); | |
964 | at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]); | |
965 | at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]); | |
966 | ||
cbe62346 | 967 | at86rf230_sleep(lp); |
7b8e19b6 | 968 | } |
969 | ||
8fad346f | 970 | static int |
e37d2ec8 | 971 | at86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel) |
8fad346f PB |
972 | { |
973 | return at86rf230_write_subreg(lp, SR_CHANNEL, channel); | |
974 | } | |
975 | ||
2d9fe7ab AA |
976 | #define AT86RF2XX_MAX_ED_LEVELS 0xF |
977 | static const s32 at86rf23x_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = { | |
978 | -9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300, | |
979 | -7100, -6900, -6700, -6500, -6300, -6100, | |
980 | }; | |
981 | ||
982 | static const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = { | |
983 | -10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, | |
179655fc | 984 | -8000, -7800, -7600, -7400, -7200, -7000, |
2d9fe7ab AA |
985 | }; |
986 | ||
987 | static const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = { | |
988 | -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000, | |
179655fc | 989 | -7800, -7600, -7400, -7200, -7000, -6800, |
2d9fe7ab AA |
990 | }; |
991 | ||
992 | static inline int | |
993 | at86rf212_update_cca_ed_level(struct at86rf230_local *lp, int rssi_base_val) | |
994 | { | |
995 | unsigned int cca_ed_thres; | |
996 | int rc; | |
997 | ||
998 | rc = at86rf230_read_subreg(lp, SR_CCA_ED_THRES, &cca_ed_thres); | |
999 | if (rc < 0) | |
1000 | return rc; | |
1001 | ||
1002 | switch (rssi_base_val) { | |
1003 | case -98: | |
1004 | lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98; | |
1005 | lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98); | |
1006 | lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres]; | |
1007 | break; | |
1008 | case -100: | |
1009 | lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100; | |
1010 | lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100); | |
1011 | lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres]; | |
1012 | break; | |
1013 | default: | |
1014 | WARN_ON(1); | |
1015 | } | |
1016 | ||
1017 | return 0; | |
1018 | } | |
1019 | ||
8fad346f | 1020 | static int |
e37d2ec8 | 1021 | at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel) |
8fad346f PB |
1022 | { |
1023 | int rc; | |
1024 | ||
1025 | if (channel == 0) | |
1026 | rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0); | |
1027 | else | |
1028 | rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1); | |
1029 | if (rc < 0) | |
1030 | return rc; | |
1031 | ||
6ca00197 | 1032 | if (page == 0) { |
643e53c2 | 1033 | rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0); |
a53d1f7c | 1034 | lp->data->rssi_base_val = -100; |
6ca00197 | 1035 | } else { |
643e53c2 | 1036 | rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1); |
a53d1f7c | 1037 | lp->data->rssi_base_val = -98; |
6ca00197 | 1038 | } |
643e53c2 PB |
1039 | if (rc < 0) |
1040 | return rc; | |
1041 | ||
2d9fe7ab AA |
1042 | rc = at86rf212_update_cca_ed_level(lp, lp->data->rssi_base_val); |
1043 | if (rc < 0) | |
1044 | return rc; | |
1045 | ||
24ccb9f4 AA |
1046 | /* This sets the symbol_duration according frequency on the 212. |
1047 | * TODO move this handling while set channel and page in cfg802154. | |
1048 | * We can do that, this timings are according 802.15.4 standard. | |
1049 | * If we do that in cfg802154, this is a more generic calculation. | |
1050 | * | |
1051 | * This should also protected from ifs_timer. Means cancel timer and | |
1052 | * init with a new value. For now, this is okay. | |
1053 | */ | |
1054 | if (channel == 0) { | |
1055 | if (page == 0) { | |
1056 | /* SUB:0 and BPSK:0 -> BPSK-20 */ | |
1057 | lp->hw->phy->symbol_duration = 50; | |
1058 | } else { | |
1059 | /* SUB:1 and BPSK:0 -> BPSK-40 */ | |
1060 | lp->hw->phy->symbol_duration = 25; | |
1061 | } | |
1062 | } else { | |
1063 | if (page == 0) | |
2d6dde29 | 1064 | /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */ |
24ccb9f4 AA |
1065 | lp->hw->phy->symbol_duration = 40; |
1066 | else | |
2d6dde29 | 1067 | /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */ |
24ccb9f4 AA |
1068 | lp->hw->phy->symbol_duration = 16; |
1069 | } | |
1070 | ||
1071 | lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD * | |
1072 | lp->hw->phy->symbol_duration; | |
1073 | lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD * | |
1074 | lp->hw->phy->symbol_duration; | |
1075 | ||
8fad346f PB |
1076 | return at86rf230_write_subreg(lp, SR_CHANNEL, channel); |
1077 | } | |
1078 | ||
7b8e19b6 | 1079 | static int |
e37d2ec8 | 1080 | at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel) |
7b8e19b6 | 1081 | { |
5a504397 | 1082 | struct at86rf230_local *lp = hw->priv; |
7b8e19b6 | 1083 | int rc; |
1084 | ||
a53d1f7c | 1085 | rc = lp->data->set_channel(lp, page, channel); |
984e0c68 AA |
1086 | /* Wait for PLL */ |
1087 | usleep_range(lp->data->t_channel_switch, | |
1088 | lp->data->t_channel_switch + 10); | |
dce481e6 AA |
1089 | |
1090 | lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; | |
820bd66f | 1091 | return rc; |
7b8e19b6 | 1092 | } |
1093 | ||
1486774d | 1094 | static int |
5a504397 | 1095 | at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, |
1486774d | 1096 | struct ieee802154_hw_addr_filt *filt, |
1097 | unsigned long changed) | |
1098 | { | |
5a504397 | 1099 | struct at86rf230_local *lp = hw->priv; |
1486774d | 1100 | |
57205c14 | 1101 | if (changed & IEEE802154_AFILT_SADDR_CHANGED) { |
b70ab2e8 PB |
1102 | u16 addr = le16_to_cpu(filt->short_addr); |
1103 | ||
1486774d | 1104 | dev_vdbg(&lp->spi->dev, |
e80fb5ee | 1105 | "at86rf230_set_hw_addr_filt called for saddr\n"); |
b70ab2e8 PB |
1106 | __at86rf230_write(lp, RG_SHORT_ADDR_0, addr); |
1107 | __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8); | |
1486774d | 1108 | } |
1109 | ||
57205c14 | 1110 | if (changed & IEEE802154_AFILT_PANID_CHANGED) { |
b70ab2e8 PB |
1111 | u16 pan = le16_to_cpu(filt->pan_id); |
1112 | ||
1486774d | 1113 | dev_vdbg(&lp->spi->dev, |
e80fb5ee | 1114 | "at86rf230_set_hw_addr_filt called for pan id\n"); |
b70ab2e8 PB |
1115 | __at86rf230_write(lp, RG_PAN_ID_0, pan); |
1116 | __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8); | |
1486774d | 1117 | } |
1118 | ||
57205c14 | 1119 | if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { |
b70ab2e8 PB |
1120 | u8 i, addr[8]; |
1121 | ||
1122 | memcpy(addr, &filt->ieee_addr, 8); | |
1486774d | 1123 | dev_vdbg(&lp->spi->dev, |
e80fb5ee | 1124 | "at86rf230_set_hw_addr_filt called for IEEE addr\n"); |
b70ab2e8 PB |
1125 | for (i = 0; i < 8; i++) |
1126 | __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]); | |
1486774d | 1127 | } |
1128 | ||
57205c14 | 1129 | if (changed & IEEE802154_AFILT_PANC_CHANGED) { |
1486774d | 1130 | dev_vdbg(&lp->spi->dev, |
e80fb5ee | 1131 | "at86rf230_set_hw_addr_filt called for panc change\n"); |
1486774d | 1132 | if (filt->pan_coord) |
1133 | at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1); | |
1134 | else | |
1135 | at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 0); | |
1136 | } | |
1137 | ||
1138 | return 0; | |
1139 | } | |
1140 | ||
6f4da3f8 AA |
1141 | #define AT86RF23X_MAX_TX_POWERS 0xF |
1142 | static const s32 at86rf233_powers[AT86RF23X_MAX_TX_POWERS + 1] = { | |
1143 | 400, 370, 340, 300, 250, 200, 100, 0, -100, -200, -300, -400, -600, | |
1144 | -800, -1200, -1700, | |
1145 | }; | |
1146 | ||
1147 | static const s32 at86rf231_powers[AT86RF23X_MAX_TX_POWERS + 1] = { | |
1148 | 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700, | |
1149 | -900, -1200, -1700, | |
1150 | }; | |
1151 | ||
1152 | #define AT86RF212_MAX_TX_POWERS 0x1F | |
1153 | static const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = { | |
1154 | 500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700, | |
1155 | -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700, | |
1156 | -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600, | |
1157 | }; | |
1158 | ||
9b2777d6 | 1159 | static int |
6f4da3f8 | 1160 | at86rf23x_set_txpower(struct at86rf230_local *lp, s32 mbm) |
9b2777d6 | 1161 | { |
6f4da3f8 | 1162 | u32 i; |
9b2777d6 | 1163 | |
6f4da3f8 AA |
1164 | for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) { |
1165 | if (lp->hw->phy->supported.tx_powers[i] == mbm) | |
1166 | return at86rf230_write_subreg(lp, SR_TX_PWR_23X, i); | |
1167 | } | |
1168 | ||
1169 | return -EINVAL; | |
1170 | } | |
1171 | ||
1172 | static int | |
1173 | at86rf212_set_txpower(struct at86rf230_local *lp, s32 mbm) | |
1174 | { | |
1175 | u32 i; | |
1176 | ||
1177 | for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) { | |
1178 | if (lp->hw->phy->supported.tx_powers[i] == mbm) | |
1179 | return at86rf230_write_subreg(lp, SR_TX_PWR_212, i); | |
1180 | } | |
9b2777d6 | 1181 | |
6f4da3f8 AA |
1182 | return -EINVAL; |
1183 | } | |
1184 | ||
1185 | static int | |
1186 | at86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm) | |
1187 | { | |
1188 | struct at86rf230_local *lp = hw->priv; | |
9b2777d6 | 1189 | |
6f4da3f8 | 1190 | return lp->data->set_txpower(lp, mbm); |
9b2777d6 PB |
1191 | } |
1192 | ||
84dda3c6 | 1193 | static int |
5a504397 | 1194 | at86rf230_set_lbt(struct ieee802154_hw *hw, bool on) |
84dda3c6 | 1195 | { |
5a504397 | 1196 | struct at86rf230_local *lp = hw->priv; |
84dda3c6 PB |
1197 | |
1198 | return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on); | |
1199 | } | |
1200 | ||
ba08fea5 | 1201 | static int |
7fe9a388 AA |
1202 | at86rf230_set_cca_mode(struct ieee802154_hw *hw, |
1203 | const struct wpan_phy_cca *cca) | |
ba08fea5 | 1204 | { |
5a504397 | 1205 | struct at86rf230_local *lp = hw->priv; |
7fe9a388 | 1206 | u8 val; |
ba08fea5 | 1207 | |
7fe9a388 AA |
1208 | /* mapping 802.15.4 to driver spec */ |
1209 | switch (cca->mode) { | |
1210 | case NL802154_CCA_ENERGY: | |
1211 | val = 1; | |
1212 | break; | |
1213 | case NL802154_CCA_CARRIER: | |
1214 | val = 2; | |
1215 | break; | |
1216 | case NL802154_CCA_ENERGY_CARRIER: | |
1217 | switch (cca->opt) { | |
1218 | case NL802154_CCA_OPT_ENERGY_CARRIER_AND: | |
1219 | val = 3; | |
1220 | break; | |
1221 | case NL802154_CCA_OPT_ENERGY_CARRIER_OR: | |
1222 | val = 0; | |
1223 | break; | |
1224 | default: | |
1225 | return -EINVAL; | |
1226 | } | |
1227 | break; | |
1228 | default: | |
1229 | return -EINVAL; | |
1230 | } | |
1231 | ||
1232 | return at86rf230_write_subreg(lp, SR_CCA_MODE, val); | |
ba08fea5 PB |
1233 | } |
1234 | ||
a7d7eda9 | 1235 | |
6ca00197 | 1236 | static int |
32b23550 | 1237 | at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) |
6ca00197 | 1238 | { |
5a504397 | 1239 | struct at86rf230_local *lp = hw->priv; |
2d9fe7ab | 1240 | u32 i; |
6ca00197 | 1241 | |
2d9fe7ab AA |
1242 | for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) { |
1243 | if (hw->phy->supported.cca_ed_levels[i] == mbm) | |
1244 | return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, i); | |
1245 | } | |
6ca00197 | 1246 | |
2d9fe7ab | 1247 | return -EINVAL; |
6ca00197 PB |
1248 | } |
1249 | ||
f2fdd67c | 1250 | static int |
5a504397 | 1251 | at86rf230_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be, |
f2fdd67c PB |
1252 | u8 retries) |
1253 | { | |
5a504397 | 1254 | struct at86rf230_local *lp = hw->priv; |
f2fdd67c PB |
1255 | int rc; |
1256 | ||
f2fdd67c PB |
1257 | rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be); |
1258 | if (rc) | |
1259 | return rc; | |
1260 | ||
1261 | rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be); | |
1262 | if (rc) | |
1263 | return rc; | |
1264 | ||
39d7f320 | 1265 | return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, retries); |
f2fdd67c PB |
1266 | } |
1267 | ||
1268 | static int | |
5a504397 | 1269 | at86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries) |
f2fdd67c | 1270 | { |
5a504397 | 1271 | struct at86rf230_local *lp = hw->priv; |
f2fdd67c | 1272 | |
fc0719e6 | 1273 | return at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries); |
f2fdd67c PB |
1274 | } |
1275 | ||
92f45f54 AA |
1276 | static int |
1277 | at86rf230_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) | |
1278 | { | |
1279 | struct at86rf230_local *lp = hw->priv; | |
1280 | int rc; | |
1281 | ||
1282 | if (on) { | |
1283 | rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 1); | |
1284 | if (rc < 0) | |
1285 | return rc; | |
1286 | ||
1287 | rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 1); | |
1288 | if (rc < 0) | |
1289 | return rc; | |
1290 | } else { | |
1291 | rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 0); | |
1292 | if (rc < 0) | |
1293 | return rc; | |
1294 | ||
1295 | rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 0); | |
1296 | if (rc < 0) | |
1297 | return rc; | |
1298 | } | |
1299 | ||
1300 | return 0; | |
1301 | } | |
1302 | ||
16301861 | 1303 | static const struct ieee802154_ops at86rf230_ops = { |
7b8e19b6 | 1304 | .owner = THIS_MODULE, |
955aee8b | 1305 | .xmit_async = at86rf230_xmit, |
7b8e19b6 | 1306 | .ed = at86rf230_ed, |
1307 | .set_channel = at86rf230_channel, | |
1308 | .start = at86rf230_start, | |
1309 | .stop = at86rf230_stop, | |
1486774d | 1310 | .set_hw_addr_filt = at86rf230_set_hw_addr_filt, |
640985ec AA |
1311 | .set_txpower = at86rf230_set_txpower, |
1312 | .set_lbt = at86rf230_set_lbt, | |
1313 | .set_cca_mode = at86rf230_set_cca_mode, | |
1314 | .set_cca_ed_level = at86rf230_set_cca_ed_level, | |
1315 | .set_csma_params = at86rf230_set_csma_params, | |
1316 | .set_frame_retries = at86rf230_set_frame_retries, | |
92f45f54 | 1317 | .set_promiscuous_mode = at86rf230_set_promiscuous_mode, |
8fad346f PB |
1318 | }; |
1319 | ||
a53d1f7c | 1320 | static struct at86rf2xx_chip_data at86rf233_data = { |
7a4ef918 | 1321 | .t_sleep_cycle = 330, |
984e0c68 | 1322 | .t_channel_switch = 11, |
09e536cd | 1323 | .t_reset_to_off = 26, |
2e0571c0 AA |
1324 | .t_off_to_aack = 80, |
1325 | .t_off_to_tx_on = 80, | |
e6f7ed9d AA |
1326 | .t_off_to_sleep = 35, |
1327 | .t_sleep_to_off = 210, | |
1d15d6b5 AA |
1328 | .t_frame = 4096, |
1329 | .t_p_ack = 545, | |
a53d1f7c AA |
1330 | .rssi_base_val = -91, |
1331 | .set_channel = at86rf23x_set_channel, | |
6f4da3f8 | 1332 | .set_txpower = at86rf23x_set_txpower, |
a53d1f7c AA |
1333 | }; |
1334 | ||
1335 | static struct at86rf2xx_chip_data at86rf231_data = { | |
7a4ef918 | 1336 | .t_sleep_cycle = 330, |
984e0c68 | 1337 | .t_channel_switch = 24, |
09e536cd | 1338 | .t_reset_to_off = 37, |
2e0571c0 AA |
1339 | .t_off_to_aack = 110, |
1340 | .t_off_to_tx_on = 110, | |
e6f7ed9d AA |
1341 | .t_off_to_sleep = 35, |
1342 | .t_sleep_to_off = 380, | |
1d15d6b5 AA |
1343 | .t_frame = 4096, |
1344 | .t_p_ack = 545, | |
a53d1f7c AA |
1345 | .rssi_base_val = -91, |
1346 | .set_channel = at86rf23x_set_channel, | |
6f4da3f8 | 1347 | .set_txpower = at86rf23x_set_txpower, |
a53d1f7c AA |
1348 | }; |
1349 | ||
1350 | static struct at86rf2xx_chip_data at86rf212_data = { | |
7a4ef918 | 1351 | .t_sleep_cycle = 330, |
984e0c68 | 1352 | .t_channel_switch = 11, |
09e536cd | 1353 | .t_reset_to_off = 26, |
2e0571c0 AA |
1354 | .t_off_to_aack = 200, |
1355 | .t_off_to_tx_on = 200, | |
e6f7ed9d AA |
1356 | .t_off_to_sleep = 35, |
1357 | .t_sleep_to_off = 380, | |
1d15d6b5 AA |
1358 | .t_frame = 4096, |
1359 | .t_p_ack = 545, | |
a53d1f7c AA |
1360 | .rssi_base_val = -100, |
1361 | .set_channel = at86rf212_set_channel, | |
6f4da3f8 | 1362 | .set_txpower = at86rf212_set_txpower, |
a53d1f7c AA |
1363 | }; |
1364 | ||
ccdaeb2b | 1365 | static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim) |
7b8e19b6 | 1366 | { |
1db0558e | 1367 | int rc, irq_type, irq_pol = IRQ_ACTIVE_HIGH; |
f76014f7 | 1368 | unsigned int dvdd; |
f2fdd67c | 1369 | u8 csma_seed[2]; |
7b8e19b6 | 1370 | |
09e536cd | 1371 | rc = at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF); |
7dcbd22a PB |
1372 | if (rc) |
1373 | return rc; | |
7b8e19b6 | 1374 | |
4af619ae | 1375 | irq_type = irq_get_trigger_type(lp->spi->irq); |
c91799c5 AA |
1376 | if (irq_type == IRQ_TYPE_EDGE_RISING || |
1377 | irq_type == IRQ_TYPE_EDGE_FALLING) | |
1378 | dev_warn(&lp->spi->dev, | |
5c3c4736 | 1379 | "Using edge triggered irq's are not recommended, because it can cause races and result in a non-functional driver!\n"); |
702d211c AA |
1380 | if (irq_type == IRQ_TYPE_EDGE_FALLING || |
1381 | irq_type == IRQ_TYPE_LEVEL_LOW) | |
43b5abe0 | 1382 | irq_pol = IRQ_ACTIVE_LOW; |
43b5abe0 | 1383 | |
18c65049 | 1384 | rc = at86rf230_write_subreg(lp, SR_IRQ_POLARITY, irq_pol); |
43b5abe0 SH |
1385 | if (rc) |
1386 | return rc; | |
1387 | ||
6bd2b132 AA |
1388 | rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1); |
1389 | if (rc) | |
1390 | return rc; | |
1391 | ||
057dad6f | 1392 | rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END); |
7b8e19b6 | 1393 | if (rc) |
1394 | return rc; | |
1395 | ||
be64f076 AA |
1396 | /* reset values differs in at86rf231 and at86rf233 */ |
1397 | rc = at86rf230_write_subreg(lp, SR_IRQ_MASK_MODE, 0); | |
1398 | if (rc) | |
1399 | return rc; | |
1400 | ||
f2fdd67c PB |
1401 | get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed)); |
1402 | rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]); | |
1403 | if (rc) | |
1404 | return rc; | |
1405 | rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]); | |
1406 | if (rc) | |
1407 | return rc; | |
1408 | ||
7b8e19b6 | 1409 | /* CLKM changes are applied immediately */ |
1410 | rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); | |
1411 | if (rc) | |
1412 | return rc; | |
1413 | ||
1414 | /* Turn CLKM Off */ | |
1415 | rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00); | |
1416 | if (rc) | |
1417 | return rc; | |
1418 | /* Wait the next SLEEP cycle */ | |
7a4ef918 AA |
1419 | usleep_range(lp->data->t_sleep_cycle, |
1420 | lp->data->t_sleep_cycle + 100); | |
7b8e19b6 | 1421 | |
ccdaeb2b AA |
1422 | /* xtal_trim value is calculated by: |
1423 | * CL = 0.5 * (CX + CTRIM + CPAR) | |
1424 | * | |
1425 | * whereas: | |
1426 | * CL = capacitor of used crystal | |
1427 | * CX = connected capacitors at xtal pins | |
1428 | * CPAR = in all at86rf2xx datasheets this is a constant value 3 pF, | |
1429 | * but this is different on each board setup. You need to fine | |
1430 | * tuning this value via CTRIM. | |
1431 | * CTRIM = variable capacitor setting. Resolution is 0.3 pF range is | |
1432 | * 0 pF upto 4.5 pF. | |
1433 | * | |
1434 | * Examples: | |
1435 | * atben transceiver: | |
1436 | * | |
1437 | * CL = 8 pF | |
1438 | * CX = 12 pF | |
1439 | * CPAR = 3 pF (We assume the magic constant from datasheet) | |
1440 | * CTRIM = 0.9 pF | |
1441 | * | |
1442 | * (12+0.9+3)/2 = 7.95 which is nearly at 8 pF | |
1443 | * | |
1444 | * xtal_trim = 0x3 | |
1445 | * | |
1446 | * openlabs transceiver: | |
1447 | * | |
1448 | * CL = 16 pF | |
1449 | * CX = 22 pF | |
1450 | * CPAR = 3 pF (We assume the magic constant from datasheet) | |
1451 | * CTRIM = 4.5 pF | |
1452 | * | |
1453 | * (22+4.5+3)/2 = 14.75 which is the nearest value to 16 pF | |
1454 | * | |
1455 | * xtal_trim = 0xf | |
1456 | */ | |
1457 | rc = at86rf230_write_subreg(lp, SR_XTAL_TRIM, xtal_trim); | |
1458 | if (rc) | |
1459 | return rc; | |
1460 | ||
1cc9fc53 | 1461 | rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd); |
7b8e19b6 | 1462 | if (rc) |
1463 | return rc; | |
1cc9fc53 | 1464 | if (!dvdd) { |
7b8e19b6 | 1465 | dev_err(&lp->spi->dev, "DVDD error\n"); |
1466 | return -EINVAL; | |
1467 | } | |
1468 | ||
05e3f2f3 AA |
1469 | /* Force setting slotted operation bit to 0. Sometimes the atben |
1470 | * sets this bit and I don't know why. We set this always force | |
1471 | * to zero while probing. | |
1472 | */ | |
6cc6399c | 1473 | return at86rf230_write_subreg(lp, SR_SLOTTED_OPERATION, 0); |
7b8e19b6 | 1474 | } |
1475 | ||
aaa1c4d2 | 1476 | static int |
ccdaeb2b AA |
1477 | at86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr, |
1478 | u8 *xtal_trim) | |
fa2d3e94 | 1479 | { |
aaa1c4d2 | 1480 | struct at86rf230_platform_data *pdata = spi->dev.platform_data; |
ccdaeb2b | 1481 | int ret; |
fa2d3e94 | 1482 | |
aaa1c4d2 AA |
1483 | if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node) { |
1484 | if (!pdata) | |
1485 | return -ENOENT; | |
fa2d3e94 | 1486 | |
aaa1c4d2 AA |
1487 | *rstn = pdata->rstn; |
1488 | *slp_tr = pdata->slp_tr; | |
ccdaeb2b | 1489 | *xtal_trim = pdata->xtal_trim; |
aaa1c4d2 AA |
1490 | return 0; |
1491 | } | |
fa2d3e94 | 1492 | |
aaa1c4d2 AA |
1493 | *rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); |
1494 | *slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0); | |
ccdaeb2b AA |
1495 | ret = of_property_read_u8(spi->dev.of_node, "xtal-trim", xtal_trim); |
1496 | if (ret < 0 && ret != -EINVAL) | |
1497 | return ret; | |
fa2d3e94 | 1498 | |
aaa1c4d2 | 1499 | return 0; |
fa2d3e94 AA |
1500 | } |
1501 | ||
c8ee0f56 AA |
1502 | static int |
1503 | at86rf230_detect_device(struct at86rf230_local *lp) | |
1504 | { | |
1505 | unsigned int part, version, val; | |
1506 | u16 man_id = 0; | |
1507 | const char *chip; | |
1508 | int rc; | |
1509 | ||
1510 | rc = __at86rf230_read(lp, RG_MAN_ID_0, &val); | |
1511 | if (rc) | |
1512 | return rc; | |
1513 | man_id |= val; | |
1514 | ||
1515 | rc = __at86rf230_read(lp, RG_MAN_ID_1, &val); | |
1516 | if (rc) | |
1517 | return rc; | |
1518 | man_id |= (val << 8); | |
1519 | ||
1520 | rc = __at86rf230_read(lp, RG_PART_NUM, &part); | |
1521 | if (rc) | |
1522 | return rc; | |
1523 | ||
7598968d | 1524 | rc = __at86rf230_read(lp, RG_VERSION_NUM, &version); |
c8ee0f56 AA |
1525 | if (rc) |
1526 | return rc; | |
1527 | ||
1528 | if (man_id != 0x001f) { | |
1529 | dev_err(&lp->spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", | |
1530 | man_id >> 8, man_id & 0xFF); | |
1531 | return -EINVAL; | |
1532 | } | |
1533 | ||
f265be3d | 1534 | lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | |
edea8f7c AA |
1535 | IEEE802154_HW_CSMA_PARAMS | |
1536 | IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT | | |
1537 | IEEE802154_HW_PROMISCUOUS; | |
1538 | ||
1539 | lp->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | | |
1540 | WPAN_PHY_FLAG_CCA_ED_LEVEL | | |
1541 | WPAN_PHY_FLAG_CCA_MODE; | |
c8ee0f56 | 1542 | |
8377d22c AA |
1543 | lp->hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) | |
1544 | BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER); | |
1545 | lp->hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) | | |
1546 | BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR); | |
1547 | ||
2d9fe7ab AA |
1548 | lp->hw->phy->supported.cca_ed_levels = at86rf23x_ed_levels; |
1549 | lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf23x_ed_levels); | |
1550 | ||
b48a7c18 AA |
1551 | lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; |
1552 | ||
c8ee0f56 AA |
1553 | switch (part) { |
1554 | case 2: | |
1555 | chip = "at86rf230"; | |
1556 | rc = -ENOTSUPP; | |
cc643496 | 1557 | goto not_supp; |
c8ee0f56 AA |
1558 | case 3: |
1559 | chip = "at86rf231"; | |
a53d1f7c | 1560 | lp->data = &at86rf231_data; |
72f655e4 | 1561 | lp->hw->phy->supported.channels[0] = 0x7FFF800; |
fe58d016 | 1562 | lp->hw->phy->current_channel = 11; |
24ccb9f4 | 1563 | lp->hw->phy->symbol_duration = 16; |
6f4da3f8 AA |
1564 | lp->hw->phy->supported.tx_powers = at86rf231_powers; |
1565 | lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf231_powers); | |
c8ee0f56 AA |
1566 | break; |
1567 | case 7: | |
1568 | chip = "at86rf212"; | |
4ecc8a55 AY |
1569 | lp->data = &at86rf212_data; |
1570 | lp->hw->flags |= IEEE802154_HW_LBT; | |
72f655e4 AA |
1571 | lp->hw->phy->supported.channels[0] = 0x00007FF; |
1572 | lp->hw->phy->supported.channels[2] = 0x00007FF; | |
4ecc8a55 AY |
1573 | lp->hw->phy->current_channel = 5; |
1574 | lp->hw->phy->symbol_duration = 25; | |
8377d22c | 1575 | lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH; |
6f4da3f8 AA |
1576 | lp->hw->phy->supported.tx_powers = at86rf212_powers; |
1577 | lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers); | |
2d9fe7ab AA |
1578 | lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100; |
1579 | lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100); | |
c8ee0f56 AA |
1580 | break; |
1581 | case 11: | |
1582 | chip = "at86rf233"; | |
a53d1f7c | 1583 | lp->data = &at86rf233_data; |
72f655e4 | 1584 | lp->hw->phy->supported.channels[0] = 0x7FFF800; |
fe58d016 | 1585 | lp->hw->phy->current_channel = 13; |
24ccb9f4 | 1586 | lp->hw->phy->symbol_duration = 16; |
6f4da3f8 AA |
1587 | lp->hw->phy->supported.tx_powers = at86rf233_powers; |
1588 | lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf233_powers); | |
c8ee0f56 AA |
1589 | break; |
1590 | default: | |
2b8b7e29 | 1591 | chip = "unknown"; |
c8ee0f56 | 1592 | rc = -ENOTSUPP; |
cc643496 | 1593 | goto not_supp; |
c8ee0f56 AA |
1594 | } |
1595 | ||
cc643496 | 1596 | lp->hw->phy->cca_ed_level = lp->hw->phy->supported.cca_ed_levels[7]; |
392f4e67 | 1597 | lp->hw->phy->transmit_power = lp->hw->phy->supported.tx_powers[0]; |
cc643496 AA |
1598 | |
1599 | not_supp: | |
c8ee0f56 AA |
1600 | dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version); |
1601 | ||
1602 | return rc; | |
1603 | } | |
1604 | ||
1d15d6b5 AA |
1605 | static void |
1606 | at86rf230_setup_spi_messages(struct at86rf230_local *lp) | |
1607 | { | |
2e0571c0 | 1608 | lp->state.lp = lp; |
cca990c8 | 1609 | lp->state.irq = lp->spi->irq; |
2e0571c0 AA |
1610 | spi_message_init(&lp->state.msg); |
1611 | lp->state.msg.context = &lp->state; | |
263be332 | 1612 | lp->state.trx.len = 2; |
2e0571c0 AA |
1613 | lp->state.trx.tx_buf = lp->state.buf; |
1614 | lp->state.trx.rx_buf = lp->state.buf; | |
1615 | spi_message_add_tail(&lp->state.trx, &lp->state.msg); | |
eb3b435e AA |
1616 | hrtimer_init(&lp->state.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
1617 | lp->state.timer.function = at86rf230_async_state_timer; | |
2e0571c0 | 1618 | |
1d15d6b5 | 1619 | lp->irq.lp = lp; |
cca990c8 | 1620 | lp->irq.irq = lp->spi->irq; |
1d15d6b5 AA |
1621 | spi_message_init(&lp->irq.msg); |
1622 | lp->irq.msg.context = &lp->irq; | |
263be332 | 1623 | lp->irq.trx.len = 2; |
1d15d6b5 AA |
1624 | lp->irq.trx.tx_buf = lp->irq.buf; |
1625 | lp->irq.trx.rx_buf = lp->irq.buf; | |
1626 | spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); | |
eb3b435e AA |
1627 | hrtimer_init(&lp->irq.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
1628 | lp->irq.timer.function = at86rf230_async_state_timer; | |
1d15d6b5 AA |
1629 | |
1630 | lp->tx.lp = lp; | |
cca990c8 | 1631 | lp->tx.irq = lp->spi->irq; |
1d15d6b5 AA |
1632 | spi_message_init(&lp->tx.msg); |
1633 | lp->tx.msg.context = &lp->tx; | |
263be332 | 1634 | lp->tx.trx.len = 2; |
1d15d6b5 AA |
1635 | lp->tx.trx.tx_buf = lp->tx.buf; |
1636 | lp->tx.trx.rx_buf = lp->tx.buf; | |
1637 | spi_message_add_tail(&lp->tx.trx, &lp->tx.msg); | |
eb3b435e AA |
1638 | hrtimer_init(&lp->tx.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
1639 | lp->tx.timer.function = at86rf230_async_state_timer; | |
1d15d6b5 AA |
1640 | } |
1641 | ||
493bc90a AA |
1642 | #ifdef CONFIG_IEEE802154_AT86RF230_DEBUGFS |
1643 | static struct dentry *at86rf230_debugfs_root; | |
1644 | ||
1645 | static int at86rf230_stats_show(struct seq_file *file, void *offset) | |
1646 | { | |
1647 | struct at86rf230_local *lp = file->private; | |
493bc90a | 1648 | |
97170ea1 SR |
1649 | seq_printf(file, "SUCCESS:\t\t%8llu\n", lp->trac.success); |
1650 | seq_printf(file, "SUCCESS_DATA_PENDING:\t%8llu\n", | |
1651 | lp->trac.success_data_pending); | |
1652 | seq_printf(file, "SUCCESS_WAIT_FOR_ACK:\t%8llu\n", | |
1653 | lp->trac.success_wait_for_ack); | |
1654 | seq_printf(file, "CHANNEL_ACCESS_FAILURE:\t%8llu\n", | |
1655 | lp->trac.channel_access_failure); | |
1656 | seq_printf(file, "NO_ACK:\t\t\t%8llu\n", lp->trac.no_ack); | |
1657 | seq_printf(file, "INVALID:\t\t%8llu\n", lp->trac.invalid); | |
1658 | return 0; | |
493bc90a AA |
1659 | } |
1660 | ||
1661 | static int at86rf230_stats_open(struct inode *inode, struct file *file) | |
1662 | { | |
1663 | return single_open(file, at86rf230_stats_show, inode->i_private); | |
1664 | } | |
1665 | ||
1666 | static const struct file_operations at86rf230_stats_fops = { | |
1667 | .open = at86rf230_stats_open, | |
1668 | .read = seq_read, | |
1669 | .llseek = seq_lseek, | |
1670 | .release = single_release, | |
1671 | }; | |
1672 | ||
1673 | static int at86rf230_debugfs_init(struct at86rf230_local *lp) | |
1674 | { | |
1675 | char debugfs_dir_name[DNAME_INLINE_LEN + 1] = "at86rf230-"; | |
1676 | struct dentry *stats; | |
1677 | ||
1678 | strncat(debugfs_dir_name, dev_name(&lp->spi->dev), DNAME_INLINE_LEN); | |
1679 | ||
1680 | at86rf230_debugfs_root = debugfs_create_dir(debugfs_dir_name, NULL); | |
1681 | if (!at86rf230_debugfs_root) | |
1682 | return -ENOMEM; | |
1683 | ||
1684 | stats = debugfs_create_file("trac_stats", S_IRUGO, | |
1685 | at86rf230_debugfs_root, lp, | |
1686 | &at86rf230_stats_fops); | |
1687 | if (!stats) | |
1688 | return -ENOMEM; | |
1689 | ||
1690 | return 0; | |
1691 | } | |
1692 | ||
1693 | static void at86rf230_debugfs_remove(void) | |
1694 | { | |
1695 | debugfs_remove_recursive(at86rf230_debugfs_root); | |
1696 | } | |
1697 | #else | |
1698 | static int at86rf230_debugfs_init(struct at86rf230_local *lp) { return 0; } | |
1699 | static void at86rf230_debugfs_remove(void) { } | |
1700 | #endif | |
1701 | ||
bb1f4606 | 1702 | static int at86rf230_probe(struct spi_device *spi) |
7b8e19b6 | 1703 | { |
5a504397 | 1704 | struct ieee802154_hw *hw; |
7b8e19b6 | 1705 | struct at86rf230_local *lp; |
f76014f7 | 1706 | unsigned int status; |
aaa1c4d2 | 1707 | int rc, irq_type, rstn, slp_tr; |
e3721749 | 1708 | u8 xtal_trim = 0; |
7b8e19b6 | 1709 | |
1710 | if (!spi->irq) { | |
1711 | dev_err(&spi->dev, "no IRQ specified\n"); | |
1712 | return -EINVAL; | |
1713 | } | |
1714 | ||
ccdaeb2b | 1715 | rc = at86rf230_get_pdata(spi, &rstn, &slp_tr, &xtal_trim); |
aaa1c4d2 AA |
1716 | if (rc < 0) { |
1717 | dev_err(&spi->dev, "failed to parse platform_data: %d\n", rc); | |
1718 | return rc; | |
43b5abe0 SH |
1719 | } |
1720 | ||
aaa1c4d2 AA |
1721 | if (gpio_is_valid(rstn)) { |
1722 | rc = devm_gpio_request_one(&spi->dev, rstn, | |
0679e29b | 1723 | GPIOF_OUT_INIT_HIGH, "rstn"); |
3fa27571 AA |
1724 | if (rc) |
1725 | return rc; | |
1726 | } | |
7b8e19b6 | 1727 | |
aaa1c4d2 AA |
1728 | if (gpio_is_valid(slp_tr)) { |
1729 | rc = devm_gpio_request_one(&spi->dev, slp_tr, | |
0679e29b | 1730 | GPIOF_OUT_INIT_LOW, "slp_tr"); |
7b8e19b6 | 1731 | if (rc) |
0679e29b | 1732 | return rc; |
7b8e19b6 | 1733 | } |
1734 | ||
1735 | /* Reset */ | |
aaa1c4d2 | 1736 | if (gpio_is_valid(rstn)) { |
3fa27571 | 1737 | udelay(1); |
aaa1c4d2 | 1738 | gpio_set_value(rstn, 0); |
3fa27571 | 1739 | udelay(1); |
aaa1c4d2 | 1740 | gpio_set_value(rstn, 1); |
3fa27571 AA |
1741 | usleep_range(120, 240); |
1742 | } | |
7b8e19b6 | 1743 | |
5a504397 AA |
1744 | hw = ieee802154_alloc_hw(sizeof(*lp), &at86rf230_ops); |
1745 | if (!hw) | |
640985ec AA |
1746 | return -ENOMEM; |
1747 | ||
5a504397 AA |
1748 | lp = hw->priv; |
1749 | lp->hw = hw; | |
640985ec | 1750 | lp->spi = spi; |
d2c8bf51 | 1751 | lp->slp_tr = slp_tr; |
5a504397 | 1752 | hw->parent = &spi->dev; |
f6f4e86a | 1753 | ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); |
8fad346f | 1754 | |
f76014f7 AA |
1755 | lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config); |
1756 | if (IS_ERR(lp->regmap)) { | |
1757 | rc = PTR_ERR(lp->regmap); | |
1758 | dev_err(&spi->dev, "Failed to allocate register map: %d\n", | |
1759 | rc); | |
1760 | goto free_dev; | |
1761 | } | |
1762 | ||
1d15d6b5 AA |
1763 | at86rf230_setup_spi_messages(lp); |
1764 | ||
c8ee0f56 AA |
1765 | rc = at86rf230_detect_device(lp); |
1766 | if (rc < 0) | |
1767 | goto free_dev; | |
1768 | ||
2e0571c0 | 1769 | init_completion(&lp->state_complete); |
8fad346f PB |
1770 | |
1771 | spi_set_drvdata(spi, lp); | |
1772 | ||
ccdaeb2b | 1773 | rc = at86rf230_hw_init(lp, xtal_trim); |
7b8e19b6 | 1774 | if (rc) |
1d15d6b5 | 1775 | goto free_dev; |
7b8e19b6 | 1776 | |
19626946 AA |
1777 | /* Read irq status register to reset irq line */ |
1778 | rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); | |
7b8e19b6 | 1779 | if (rc) |
1d15d6b5 | 1780 | goto free_dev; |
7b8e19b6 | 1781 | |
1d15d6b5 AA |
1782 | irq_type = irq_get_trigger_type(spi->irq); |
1783 | if (!irq_type) | |
9ff19e6f | 1784 | irq_type = IRQF_TRIGGER_HIGH; |
1d15d6b5 AA |
1785 | |
1786 | rc = devm_request_irq(&spi->dev, spi->irq, at86rf230_isr, | |
1787 | IRQF_SHARED | irq_type, dev_name(&spi->dev), lp); | |
057dad6f | 1788 | if (rc) |
1d15d6b5 | 1789 | goto free_dev; |
057dad6f | 1790 | |
e6f7ed9d AA |
1791 | /* disable_irq by default and wait for starting hardware */ |
1792 | disable_irq(spi->irq); | |
1793 | ||
1794 | /* going into sleep by default */ | |
cbe62346 | 1795 | at86rf230_sleep(lp); |
e6f7ed9d | 1796 | |
493bc90a | 1797 | rc = at86rf230_debugfs_init(lp); |
7b8e19b6 | 1798 | if (rc) |
1d15d6b5 | 1799 | goto free_dev; |
7b8e19b6 | 1800 | |
493bc90a AA |
1801 | rc = ieee802154_register_hw(lp->hw); |
1802 | if (rc) | |
1803 | goto free_debugfs; | |
1804 | ||
7b8e19b6 | 1805 | return rc; |
1806 | ||
493bc90a AA |
1807 | free_debugfs: |
1808 | at86rf230_debugfs_remove(); | |
640985ec | 1809 | free_dev: |
5a504397 | 1810 | ieee802154_free_hw(lp->hw); |
8fad346f | 1811 | |
7b8e19b6 | 1812 | return rc; |
1813 | } | |
1814 | ||
bb1f4606 | 1815 | static int at86rf230_remove(struct spi_device *spi) |
7b8e19b6 | 1816 | { |
1817 | struct at86rf230_local *lp = spi_get_drvdata(spi); | |
1818 | ||
17e84a92 AA |
1819 | /* mask all at86rf230 irq's */ |
1820 | at86rf230_write_subreg(lp, SR_IRQ_MASK, 0); | |
5a504397 AA |
1821 | ieee802154_unregister_hw(lp->hw); |
1822 | ieee802154_free_hw(lp->hw); | |
493bc90a | 1823 | at86rf230_debugfs_remove(); |
7b8e19b6 | 1824 | dev_dbg(&spi->dev, "unregistered at86rf230\n"); |
0679e29b | 1825 | |
7b8e19b6 | 1826 | return 0; |
1827 | } | |
1828 | ||
1086b4f6 | 1829 | static const struct of_device_id at86rf230_of_match[] = { |
fa2d3e94 AA |
1830 | { .compatible = "atmel,at86rf230", }, |
1831 | { .compatible = "atmel,at86rf231", }, | |
1832 | { .compatible = "atmel,at86rf233", }, | |
1833 | { .compatible = "atmel,at86rf212", }, | |
1834 | { }, | |
1835 | }; | |
835cb7d2 | 1836 | MODULE_DEVICE_TABLE(of, at86rf230_of_match); |
fa2d3e94 | 1837 | |
90b15520 AA |
1838 | static const struct spi_device_id at86rf230_device_id[] = { |
1839 | { .name = "at86rf230", }, | |
1840 | { .name = "at86rf231", }, | |
1841 | { .name = "at86rf233", }, | |
1842 | { .name = "at86rf212", }, | |
1843 | { }, | |
1844 | }; | |
1845 | MODULE_DEVICE_TABLE(spi, at86rf230_device_id); | |
1846 | ||
7b8e19b6 | 1847 | static struct spi_driver at86rf230_driver = { |
90b15520 | 1848 | .id_table = at86rf230_device_id, |
7b8e19b6 | 1849 | .driver = { |
fa2d3e94 | 1850 | .of_match_table = of_match_ptr(at86rf230_of_match), |
7b8e19b6 | 1851 | .name = "at86rf230", |
1852 | .owner = THIS_MODULE, | |
1853 | }, | |
1854 | .probe = at86rf230_probe, | |
bb1f4606 | 1855 | .remove = at86rf230_remove, |
7b8e19b6 | 1856 | }; |
1857 | ||
395a5738 | 1858 | module_spi_driver(at86rf230_driver); |
7b8e19b6 | 1859 | |
1860 | MODULE_DESCRIPTION("AT86RF230 Transceiver Driver"); | |
1861 | MODULE_LICENSE("GPL v2"); |