Commit 2719a9e7 authored by Linus Walleij's avatar Linus Walleij Committed by Kalle Valo

wifi: cw1200: Convert to GPIO descriptors

The CW1200 uses two GPIOs to control the powerup and reset
pins, get these from GPIO descriptors instead of being passed
as platform data from boardfiles.

The RESET line will need to be marked as active low as we will
let gpiolib handle the polarity inversion.

The SDIO case is a bit special since the "card" need to be
powered up before it gets detected on the SDIO bus and
properly probed. Fix this by using board-specific GPIOs
assigned to device "NULL".

There are currently no in-tree users.
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://msgid.link/20240131-descriptors-wireless-v1-6-e1c7c5d68746@linaro.org
parent d8da5a21
......@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
......@@ -178,12 +178,15 @@ static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self)
return ret;
}
/* Like the rest of the driver, this only supports one device per system */
static struct gpio_desc *cw1200_reset;
static struct gpio_desc *cw1200_powerup;
static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
{
if (pdata->reset) {
gpio_set_value(pdata->reset, 0);
if (cw1200_reset) {
gpiod_set_value(cw1200_reset, 0);
msleep(30); /* Min is 2 * CLK32K cycles */
gpio_free(pdata->reset);
}
if (pdata->power_ctrl)
......@@ -196,16 +199,21 @@ static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
{
/* Ensure I/Os are pulled low */
if (pdata->reset) {
gpio_request(pdata->reset, "cw1200_wlan_reset");
gpio_direction_output(pdata->reset, 0);
/* Ensure I/Os are pulled low (reset is active low) */
cw1200_reset = devm_gpiod_get_optional(NULL, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(cw1200_reset)) {
pr_err("could not get CW1200 SDIO reset GPIO\n");
return PTR_ERR(cw1200_reset);
}
if (pdata->powerup) {
gpio_request(pdata->powerup, "cw1200_wlan_powerup");
gpio_direction_output(pdata->powerup, 0);
gpiod_set_consumer_name(cw1200_reset, "cw1200_wlan_reset");
cw1200_powerup = devm_gpiod_get_optional(NULL, "powerup", GPIOD_OUT_LOW);
if (IS_ERR(cw1200_powerup)) {
pr_err("could not get CW1200 SDIO powerup GPIO\n");
return PTR_ERR(cw1200_powerup);
}
if (pdata->reset || pdata->powerup)
gpiod_set_consumer_name(cw1200_powerup, "cw1200_wlan_powerup");
if (cw1200_reset || cw1200_powerup)
msleep(10); /* Settle time? */
/* Enable 3v3 and 1v8 to hardware */
......@@ -226,13 +234,13 @@ static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
}
/* Enable POWERUP signal */
if (pdata->powerup) {
gpio_set_value(pdata->powerup, 1);
if (cw1200_powerup) {
gpiod_set_value(cw1200_powerup, 1);
msleep(250); /* or more..? */
}
/* Enable RSTn signal */
if (pdata->reset) {
gpio_set_value(pdata->reset, 1);
/* Deassert RSTn signal, note active low */
if (cw1200_reset) {
gpiod_set_value(cw1200_reset, 0);
msleep(50); /* Or more..? */
}
return 0;
......
......@@ -11,7 +11,7 @@
*/
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
......@@ -38,6 +38,8 @@ struct hwbus_priv {
const struct cw1200_platform_data_spi *pdata;
spinlock_t lock; /* Serialize all bus operations */
wait_queue_head_t wq;
struct gpio_desc *reset;
struct gpio_desc *powerup;
int claimed;
};
......@@ -269,12 +271,12 @@ static void cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
free_irq(self->func->irq, self);
}
static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
static int cw1200_spi_off(struct hwbus_priv *self, const struct cw1200_platform_data_spi *pdata)
{
if (pdata->reset) {
gpio_set_value(pdata->reset, 0);
if (self->reset) {
/* Assert RESET, note active low */
gpiod_set_value(self->reset, 1);
msleep(30); /* Min is 2 * CLK32K cycles */
gpio_free(pdata->reset);
}
if (pdata->power_ctrl)
......@@ -285,18 +287,12 @@ static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
return 0;
}
static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
static int cw1200_spi_on(struct hwbus_priv *self, const struct cw1200_platform_data_spi *pdata)
{
/* Ensure I/Os are pulled low */
if (pdata->reset) {
gpio_request(pdata->reset, "cw1200_wlan_reset");
gpio_direction_output(pdata->reset, 0);
}
if (pdata->powerup) {
gpio_request(pdata->powerup, "cw1200_wlan_powerup");
gpio_direction_output(pdata->powerup, 0);
}
if (pdata->reset || pdata->powerup)
gpiod_direction_output(self->reset, 1); /* Active low */
gpiod_direction_output(self->powerup, 0);
if (self->reset || self->powerup)
msleep(10); /* Settle time? */
/* Enable 3v3 and 1v8 to hardware */
......@@ -317,13 +313,13 @@ static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
}
/* Enable POWERUP signal */
if (pdata->powerup) {
gpio_set_value(pdata->powerup, 1);
if (self->powerup) {
gpiod_set_value(self->powerup, 1);
msleep(250); /* or more..? */
}
/* Enable RSTn signal */
if (pdata->reset) {
gpio_set_value(pdata->reset, 1);
/* Assert RSTn signal, note active low */
if (self->reset) {
gpiod_set_value(self->reset, 0);
msleep(50); /* Or more..? */
}
return 0;
......@@ -375,20 +371,33 @@ static int cw1200_spi_probe(struct spi_device *func)
spi_get_chipselect(func, 0), func->mode, func->bits_per_word,
func->max_speed_hz);
if (cw1200_spi_on(plat_data)) {
self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
if (!self) {
pr_err("Can't allocate SPI hwbus_priv.");
return -ENOMEM;
}
/* Request reset asserted */
self->reset = devm_gpiod_get_optional(&func->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(self->reset))
return dev_err_probe(&func->dev, PTR_ERR(self->reset),
"could not get reset GPIO\n");
gpiod_set_consumer_name(self->reset, "cw1200_wlan_reset");
self->powerup = devm_gpiod_get_optional(&func->dev, "powerup", GPIOD_OUT_LOW);
if (IS_ERR(self->powerup))
return dev_err_probe(&func->dev, PTR_ERR(self->powerup),
"could not get powerup GPIO\n");
gpiod_set_consumer_name(self->reset, "cw1200_wlan_powerup");
if (cw1200_spi_on(self, plat_data)) {
pr_err("spi_on() failed!\n");
return -1;
return -ENODEV;
}
if (spi_setup(func)) {
pr_err("spi_setup() failed!\n");
return -1;
}
self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
if (!self) {
pr_err("Can't allocate SPI hwbus_priv.");
return -ENOMEM;
return -ENODEV;
}
self->pdata = plat_data;
......@@ -410,7 +419,7 @@ static int cw1200_spi_probe(struct spi_device *func)
if (status) {
cw1200_spi_irq_unsubscribe(self);
cw1200_spi_off(plat_data);
cw1200_spi_off(self, plat_data);
}
return status;
......@@ -428,7 +437,7 @@ static void cw1200_spi_disconnect(struct spi_device *func)
self->core = NULL;
}
}
cw1200_spi_off(dev_get_platdata(&func->dev));
cw1200_spi_off(self, dev_get_platdata(&func->dev));
}
static int __maybe_unused cw1200_spi_suspend(struct device *dev)
......
......@@ -14,8 +14,6 @@ struct cw1200_platform_data_spi {
/* All others are optional */
bool have_5ghz;
int reset; /* GPIO to RSTn signal (0 disables) */
int powerup; /* GPIO to POWERUP signal (0 disables) */
int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata,
bool enable); /* Control 3v3 / 1v8 supply */
int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata,
......@@ -30,8 +28,6 @@ struct cw1200_platform_data_sdio {
/* All others are optional */
bool have_5ghz;
bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */
int reset; /* GPIO to RSTn signal (0 disables) */
int powerup; /* GPIO to POWERUP signal (0 disables) */
int irq; /* IRQ line or 0 to use SDIO IRQ */
int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata,
bool enable); /* Control 3v3 / 1v8 supply */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment