diff options
Diffstat (limited to 'drivers/net/wireless/ti/wl1251/spi.c')
| -rw-r--r-- | drivers/net/wireless/ti/wl1251/spi.c | 115 | 
1 files changed, 74 insertions, 41 deletions
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index c7dc6feab2f..a0aa8fa7239 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -23,9 +23,14 @@  #include <linux/irq.h>  #include <linux/module.h>  #include <linux/slab.h> +#include <linux/swab.h>  #include <linux/crc7.h>  #include <linux/spi/spi.h>  #include <linux/wl12xx.h> +#include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h>  #include "wl1251.h"  #include "reg.h" @@ -79,47 +84,44 @@ static void wl1251_spi_reset(struct wl1251 *wl)  static void wl1251_spi_wake(struct wl1251 *wl)  { -	u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;  	struct spi_transfer t;  	struct spi_message m; +	u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); -	cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);  	if (!cmd) {  		wl1251_error("could not allocate cmd for spi init");  		return;  	} -	memset(crc, 0, sizeof(crc));  	memset(&t, 0, sizeof(t));  	spi_message_init(&m);  	/* Set WSPI_INIT_COMMAND  	 * the data is being send from the MSB to LSB  	 */ -	cmd[2] = 0xff; -	cmd[3] = 0xff; -	cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; -	cmd[0] = 0; -	cmd[7] = 0; -	cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; -	cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; +	cmd[0] = 0xff; +	cmd[1] = 0xff; +	cmd[2] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; +	cmd[3] = 0; +	cmd[4] = 0; +	cmd[5] = HW_ACCESS_WSPI_INIT_CMD_MASK << 3; +	cmd[5] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + +	cmd[6] = WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS +		| WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS;  	if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) -		cmd[5] |=  WSPI_INIT_CMD_DIS_FIXEDBUSY; +		cmd[6] |= WSPI_INIT_CMD_DIS_FIXEDBUSY;  	else -		cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; - -	cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS -		| WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; - -	crc[0] = cmd[1]; -	crc[1] = cmd[0]; -	crc[2] = cmd[7]; -	crc[3] = cmd[6]; -	crc[4] = cmd[5]; +		cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY; -	cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; -	cmd[4] |= WSPI_INIT_CMD_END; +	cmd[7] = crc7_be(0, cmd+2, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; +	/* +	 * The above is the logical order; it must actually be stored +	 * in the buffer byte-swapped. +	 */ +	__swab32s((u32 *)cmd); +	__swab32s((u32 *)cmd+1);  	t.tx_buf = cmd;  	t.len = WSPI_INIT_CMD_LEN; @@ -221,8 +223,8 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl)  static int wl1251_spi_set_power(struct wl1251 *wl, bool enable)  { -	if (wl->set_power) -		wl->set_power(enable); +	if (gpio_is_valid(wl->power_gpio)) +		gpio_set_value(wl->power_gpio, enable);  	return 0;  } @@ -238,13 +240,13 @@ static const struct wl1251_if_operations wl1251_spi_ops = {  static int wl1251_spi_probe(struct spi_device *spi)  { -	struct wl12xx_platform_data *pdata; +	struct wl1251_platform_data *pdata = dev_get_platdata(&spi->dev); +	struct device_node *np = spi->dev.of_node;  	struct ieee80211_hw *hw;  	struct wl1251 *wl;  	int ret; -	pdata = spi->dev.platform_data; -	if (!pdata) { +	if (!np && !pdata) {  		wl1251_error("no platform data");  		return -ENODEV;  	} @@ -271,22 +273,42 @@ static int wl1251_spi_probe(struct spi_device *spi)  		goto out_free;  	} -	wl->set_power = pdata->set_power; -	if (!wl->set_power) { -		wl1251_error("set power function missing in platform data"); -		return -ENODEV; +	if (np) { +		wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom"); +		wl->power_gpio = of_get_named_gpio(np, "ti,power-gpio", 0); +	} else if (pdata) { +		wl->power_gpio = pdata->power_gpio; +		wl->use_eeprom = pdata->use_eeprom; +	} + +	if (wl->power_gpio == -EPROBE_DEFER) { +		ret = -EPROBE_DEFER; +		goto out_free; +	} + +	if (gpio_is_valid(wl->power_gpio)) { +		ret = devm_gpio_request_one(&spi->dev, wl->power_gpio, +					GPIOF_OUT_INIT_LOW, "wl1251 power"); +		if (ret) { +			wl1251_error("Failed to request gpio: %d\n", ret); +			goto out_free; +		} +	} else { +		wl1251_error("set power gpio missing in platform data"); +		ret = -ENODEV; +		goto out_free;  	}  	wl->irq = spi->irq;  	if (wl->irq < 0) {  		wl1251_error("irq missing in platform data"); -		return -ENODEV; +		ret = -ENODEV; +		goto out_free;  	} -	wl->use_eeprom = pdata->use_eeprom; -  	irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); -	ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); +	ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0, +							DRIVER_NAME, wl);  	if (ret < 0) {  		wl1251_error("request_irq() failed: %d", ret);  		goto out_free; @@ -294,16 +316,26 @@ static int wl1251_spi_probe(struct spi_device *spi)  	irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); +	wl->vio = devm_regulator_get(&spi->dev, "vio"); +	if (IS_ERR(wl->vio)) { +		ret = PTR_ERR(wl->vio); +		wl1251_error("vio regulator missing: %d", ret); +		goto out_free; +	} + +	ret = regulator_enable(wl->vio); +	if (ret) +		goto out_free; +  	ret = wl1251_init_ieee80211(wl);  	if (ret) -		goto out_irq; +		goto disable_regulator;  	return 0; - out_irq: -	free_irq(wl->irq, wl); - - out_free: +disable_regulator: +	regulator_disable(wl->vio); +out_free:  	ieee80211_free_hw(hw);  	return ret; @@ -315,6 +347,7 @@ static int wl1251_spi_remove(struct spi_device *spi)  	free_irq(wl->irq, wl);  	wl1251_free_hw(wl); +	regulator_disable(wl->vio);  	return 0;  }  | 
