aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ieee802154
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2015-06-16 11:07:42 +0200
committerMarcel Holtmann <marcel@holtmann.org>2015-06-16 18:55:11 +0200
commitcbe6234689b07f5d1ecf2281573591ca4211a5cf (patch)
tree9f62b72191bfba93991fa45cf77e0a83edbfd8de /drivers/net/ieee802154
parentfakelb: add xmit_async after stop testcase (diff)
downloadlinux-dev-cbe6234689b07f5d1ecf2281573591ca4211a5cf.tar.xz
linux-dev-cbe6234689b07f5d1ecf2281573591ca4211a5cf.zip
at86rf230: fix phy settings while sleeping
While in sleep state then we can't access the at86rf2xx registers. This patch checks if the transceiver is in sleep state before sending spi messages via regmap. Regmap is used on every driver ops callback except for receive and xmit handling, but while receive and xmit handling the phy should not be inside the sleep state. Signed-off-by: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/net/ieee802154')
-rw-r--r--drivers/net/ieee802154/at86rf230.c88
1 files changed, 68 insertions, 20 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index 6b31f4708122..b839bbd4ff69 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -90,6 +90,7 @@ struct at86rf230_local {
struct at86rf2xx_chip_data *data;
struct regmap *regmap;
int slp_tr;
+ bool sleep;
struct completion state_complete;
struct at86rf230_state_change state;
@@ -114,18 +115,66 @@ at86rf230_async_state_change(struct at86rf230_local *lp,
const u8 state, void (*complete)(void *context),
const bool irq_enable);
+static inline void
+at86rf230_sleep(struct at86rf230_local *lp)
+{
+ if (gpio_is_valid(lp->slp_tr)) {
+ gpio_set_value(lp->slp_tr, 1);
+ usleep_range(lp->data->t_off_to_sleep,
+ lp->data->t_off_to_sleep + 10);
+ lp->sleep = true;
+ }
+}
+
+static inline void
+at86rf230_awake(struct at86rf230_local *lp)
+{
+ if (gpio_is_valid(lp->slp_tr)) {
+ gpio_set_value(lp->slp_tr, 0);
+ usleep_range(lp->data->t_sleep_to_off,
+ lp->data->t_sleep_to_off + 100);
+ lp->sleep = false;
+ }
+}
+
static inline int
__at86rf230_write(struct at86rf230_local *lp,
unsigned int addr, unsigned int data)
{
- return regmap_write(lp->regmap, addr, data);
+ bool sleep = lp->sleep;
+ int ret;
+
+ /* awake for register setting if sleep */
+ if (sleep)
+ at86rf230_awake(lp);
+
+ ret = regmap_write(lp->regmap, addr, data);
+
+ /* sleep again if was sleeping */
+ if (sleep)
+ at86rf230_sleep(lp);
+
+ return ret;
}
static inline int
__at86rf230_read(struct at86rf230_local *lp,
unsigned int addr, unsigned int *data)
{
- return regmap_read(lp->regmap, addr, data);
+ bool sleep = lp->sleep;
+ int ret;
+
+ /* awake for register setting if sleep */
+ if (sleep)
+ at86rf230_awake(lp);
+
+ ret = regmap_read(lp->regmap, addr, data);
+
+ /* sleep again if was sleeping */
+ if (sleep)
+ at86rf230_sleep(lp);
+
+ return ret;
}
static inline int
@@ -147,7 +196,20 @@ at86rf230_write_subreg(struct at86rf230_local *lp,
unsigned int addr, unsigned int mask,
unsigned int shift, unsigned int data)
{
- return regmap_update_bits(lp->regmap, addr, mask, data << shift);
+ bool sleep = lp->sleep;
+ int ret;
+
+ /* awake for register setting if sleep */
+ if (sleep)
+ at86rf230_awake(lp);
+
+ ret = regmap_update_bits(lp->regmap, addr, mask, data << shift);
+
+ /* sleep again if was sleeping */
+ if (sleep)
+ at86rf230_sleep(lp);
+
+ return ret;
}
static inline void
@@ -873,12 +935,7 @@ at86rf230_start(struct ieee802154_hw *hw)
{
struct at86rf230_local *lp = hw->priv;
- if (gpio_is_valid(lp->slp_tr)) {
- gpio_set_value(lp->slp_tr, 0);
- usleep_range(lp->data->t_sleep_to_off,
- lp->data->t_sleep_to_off + 100);
- }
-
+ at86rf230_awake(lp);
enable_irq(lp->spi->irq);
return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
@@ -892,12 +949,7 @@ at86rf230_stop(struct ieee802154_hw *hw)
at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF);
disable_irq(lp->spi->irq);
-
- if (gpio_is_valid(lp->slp_tr)) {
- gpio_set_value(lp->slp_tr, 1);
- usleep_range(lp->data->t_off_to_sleep,
- lp->data->t_off_to_sleep + 10);
- }
+ at86rf230_sleep(lp);
}
static int
@@ -1672,11 +1724,7 @@ static int at86rf230_probe(struct spi_device *spi)
disable_irq(spi->irq);
/* going into sleep by default */
- if (gpio_is_valid(slp_tr)) {
- gpio_set_value(slp_tr, 1);
- usleep_range(lp->data->t_off_to_sleep,
- lp->data->t_off_to_sleep + 10);
- }
+ at86rf230_sleep(lp);
rc = ieee802154_register_hw(lp->hw);
if (rc)