Skip to content

Commit e94f7a1

Browse files
claudiubezneacristibirsan
authored andcommitted
staging: wilc1000: handle power sequence when pins are not in DT
In case pins are not present in DT bindings for WILC devices the driver had some default pins: GPIO_NUM_RESET, GPIO_NUM_CHIP_EN. In case power pins were not located in device tree on WILC node the driver tried to request the default pins. But these pins were general and valid only on SAMA5D4 Xplained board. The patch changed this approach as follows: 1/ driver is checking if power seqeunce driver is used: if yes then it will not request DT pins and power up/down would be handled by MMC subsystem via pwrseq driver, using pm_runtime_* calls in wilc_sdio_init(), wilc_sdio_deinit() functions. In case power sequence driver is not used the wilc_wlan_power() is called. 2/ if power sequence driver is not present the driver will scan for power pins in device tree on its node. If it doens't locate any new pins and it is running on SAMA5D4 Xplained the SAMA5D4 Xplained specific pins are used. This is necessary for backward compatibility with old DTs that doesn't provide these pins. 3/ If none of the above are true the driver probe will fail. The code in netdev.c under KERNEL_VERSION(3, 13, 0) should not be necessary anymore as the replacements done in wilc_of_parse_power_pins() and wilc_wlan_power() should guarantee backward compatibility.
1 parent 953898c commit e94f7a1

9 files changed

Lines changed: 159 additions & 166 deletions

File tree

drivers/staging/wilc1000/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ ccflags-y += -I$(src)/ -DWILC_ASIC_A0 -DWILC_DEBUGFS
33

44
wilc-objs := cfg80211.o netdev.o mon.o \
55
hif.o wlan_cfg.o debugfs.o \
6-
wlan.o sysfs.o bt.o
6+
wlan.o sysfs.o bt.o power.o
77

88
obj-$(CONFIG_WILC_SDIO) += wilc-sdio.o
99
wilc-sdio-objs += $(wilc-objs)

drivers/staging/wilc1000/bt.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,9 @@ int wilc_bt_power_down(struct wilc *wilc, int source)
322322
pr_warn("Another device is preventing power down. request source is %s\n",
323323
(source == DEV_WIFI ? "Wifi" : "BT"));
324324
} else {
325-
ret = wilc_wlan_power_off_sequence(wilc);
325+
acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY, source);
326+
ret = wilc->hif_func->hif_deinit(wilc);
327+
release_bus(wilc, WILC_BUS_RELEASE_ONLY, source);
326328
if (ret) {
327329
mutex_unlock(&wilc->cs);
328330
return ret;

drivers/staging/wilc1000/hif.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,6 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
236236
void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
237237
struct cfg80211_crypto_settings *crypto);
238238
void handle_connect_cancel(struct wilc_vif *vif);
239+
int wilc_of_parse_power_pins(struct wilc *wilc);
240+
void wilc_wlan_power(struct wilc *wilc, bool on);
239241
#endif

drivers/staging/wilc1000/netdev.c

Lines changed: 0 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,152 +1347,4 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
13471347
return vif;
13481348
}
13491349

1350-
#if KERNEL_VERSION(3, 13, 0) < LINUX_VERSION_CODE
1351-
static int wilc_wlan_power(struct wilc *wilc, int power)
1352-
{
1353-
struct gpio_desc *gpio_reset;
1354-
struct gpio_desc *gpio_chip_en;
1355-
int ret = 0;
1356-
1357-
pr_info("wifi_pm : %d\n", power);
1358-
1359-
gpio_reset = gpiod_get(wilc->dt_dev, "reset", GPIOD_ASIS);
1360-
if (IS_ERR(gpio_reset)) {
1361-
dev_warn(wilc->dev, "failed to get Reset GPIO, try default\r\n");
1362-
gpio_reset = gpio_to_desc(GPIO_NUM_RESET);
1363-
if (!gpio_reset) {
1364-
dev_warn(wilc->dev,
1365-
"failed to get default Reset GPIO\r\n");
1366-
return -EIO;
1367-
}
1368-
} else {
1369-
dev_info(wilc->dev, "succesfully got gpio_reset\r\n");
1370-
}
1371-
1372-
gpio_chip_en = gpiod_get(wilc->dt_dev, "chip_en", GPIOD_ASIS);
1373-
if (IS_ERR(gpio_chip_en)) {
1374-
gpio_chip_en = gpio_to_desc(GPIO_NUM_CHIP_EN);
1375-
if (!gpio_chip_en) {
1376-
dev_warn(wilc->dev,
1377-
"failed to get default chip_en GPIO\r\n");
1378-
gpiod_put(gpio_reset);
1379-
return -EIO;
1380-
}
1381-
} else {
1382-
dev_info(wilc->dev, "succesfully got gpio_chip_en\r\n");
1383-
}
1384-
1385-
if (power) {
1386-
ret = gpiod_direction_output(gpio_chip_en, 1);
1387-
if (ret < 0) {
1388-
dev_warn(wilc->dev,
1389-
"failed to set chip_en GPIO direction\r\n");
1390-
goto out;
1391-
ret = -EIO;
1392-
}
1393-
mdelay(5);
1394-
ret = gpiod_direction_output(gpio_reset, 1);
1395-
if (ret) {
1396-
dev_warn(wilc->dev,
1397-
"failed to set reset GPIO direction\r\n");
1398-
goto out;
1399-
ret = -EIO;
1400-
}
1401-
} else {
1402-
ret = gpiod_direction_output(gpio_reset, 0);
1403-
if (ret) {
1404-
dev_warn(wilc->dev,
1405-
"failed to set chip_en GPIO direction\r\n");
1406-
goto out;
1407-
ret = -EIO;
1408-
}
1409-
ret = gpiod_direction_output(gpio_chip_en, 0);
1410-
if (ret) {
1411-
dev_warn(wilc->dev,
1412-
"failed to set reset GPIO direction\r\n");
1413-
goto out;
1414-
ret = -EIO;
1415-
}
1416-
}
1417-
1418-
out:
1419-
gpiod_put(gpio_chip_en);
1420-
gpiod_put(gpio_reset);
1421-
1422-
return ret;
1423-
}
1424-
#else
1425-
static int wilc_wlan_power(struct wilc *wilc, int power)
1426-
{
1427-
int gpio_reset;
1428-
int gpio_chip_en;
1429-
struct device_node *of_node = wilc->dt_dev->of_node;
1430-
1431-
pr_info("wifi_pm : %d\n", power);
1432-
1433-
gpio_reset = of_get_named_gpio_flags(of_node, "reset-gpios", 0, NULL);
1434-
1435-
if (gpio_reset < 0) {
1436-
gpio_reset = GPIO_NUM_RESET;
1437-
pr_info("wifi_pm : load default reset GPIO %d\n", gpio_reset);
1438-
}
1439-
1440-
gpio_chip_en = of_get_named_gpio_flags(of_node, "chip_en-gpios", 0,
1441-
NULL);
1442-
1443-
if (gpio_chip_en < 0) {
1444-
gpio_chip_en = GPIO_NUM_CHIP_EN;
1445-
pr_info("wifi_pm : load default chip_en GPIO %d\n",
1446-
gpio_chip_en);
1447-
}
1448-
1449-
if (gpio_request(gpio_chip_en, "CHIP_EN") == 0 &&
1450-
gpio_request(gpio_reset, "RESET") == 0) {
1451-
gpio_direction_output(gpio_chip_en, 0);
1452-
gpio_direction_output(gpio_reset, 0);
1453-
if (power) {
1454-
gpio_set_value(gpio_chip_en, 1);
1455-
mdelay(5);
1456-
gpio_set_value(gpio_reset, 1);
1457-
} else {
1458-
gpio_set_value(gpio_reset, 0);
1459-
gpio_set_value(gpio_chip_en, 0);
1460-
}
1461-
gpio_free(gpio_chip_en);
1462-
gpio_free(gpio_reset);
1463-
} else {
1464-
dev_err(wilc->dev,
1465-
"Error requesting GPIOs for CHIP_EN and RESET");
1466-
return -EIO;
1467-
}
1468-
1469-
return 0;
1470-
}
1471-
#endif
1472-
1473-
int wilc_wlan_power_on_sequence(struct wilc *wilc)
1474-
{
1475-
int ret;
1476-
1477-
ret = wilc_wlan_power(wilc, 0);
1478-
if (ret)
1479-
return ret;
1480-
ret = wilc_wlan_power(wilc, 1);
1481-
if (ret)
1482-
return ret;
1483-
1484-
return 0;
1485-
}
1486-
1487-
int wilc_wlan_power_off_sequence(struct wilc *wilc)
1488-
{
1489-
int ret;
1490-
1491-
ret = wilc_wlan_power(wilc, 0);
1492-
if (ret)
1493-
return ret;
1494-
1495-
return 0;
1496-
}
1497-
14981350
MODULE_LICENSE("GPL");

drivers/staging/wilc1000/netdev.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@
1313
#include <net/ieee80211_radiotap.h>
1414
#include <linux/if_arp.h>
1515
#include <linux/version.h>
16-
#if KERNEL_VERSION(3, 13, 0) < LINUX_VERSION_CODE
17-
#include <linux/gpio/consumer.h>
18-
#else
19-
#include <linux/of_gpio.h>
20-
#include <linux/gpio.h>
21-
#endif
2216

2317
#include "hif.h"
2418
#include "wlan.h"
@@ -372,7 +366,13 @@ struct wilc_vif {
372366
struct cfg80211_bss *bss;
373367
};
374368

369+
struct wilc_power_gpios {
370+
int reset;
371+
int chip_en;
372+
};
373+
375374
struct wilc_power {
375+
struct wilc_power_gpios gpios;
376376
u8 status[DEV_MAX];
377377
};
378378

drivers/staging/wilc1000/power.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#include <linux/delay.h>
2+
#include <linux/of.h>
3+
#include <linux/version.h>
4+
#include <linux/of_gpio.h>
5+
#include <linux/gpio.h>
6+
7+
#include "netdev.h"
8+
9+
/**
10+
* wilc_of_parse_power_pins() - parse power sequence pins; to keep backward
11+
* compatibility with old device trees that doesn't provide
12+
* power sequence pins we check for default pins on proper boards
13+
*
14+
* @wilc: wilc data structure
15+
*
16+
* Returns: 0 on success, negative error number on failures.
17+
*/
18+
int wilc_of_parse_power_pins(struct wilc *wilc)
19+
{
20+
static const struct wilc_power_gpios default_gpios[] = {
21+
{ .reset = GPIO_NUM_RESET, .chip_en = GPIO_NUM_CHIP_EN, },
22+
};
23+
24+
static const struct of_device_id wilc_default_pins_ids[] = {
25+
{
26+
.compatible = "atmel,sama5d4-xplained",
27+
.data = &default_gpios[0],
28+
},
29+
{ /* Sentinel. */ }
30+
};
31+
32+
struct device_node *of = wilc->dt_dev->of_node;
33+
struct wilc_power *power = &wilc->power;
34+
const struct wilc_power_gpios *gpios;
35+
const struct of_device_id *of_id;
36+
struct device_node *np;
37+
int ret = 0;
38+
39+
/*
40+
* The maching here is to keep backward compatibility with old DT that
41+
* doesn't provide reset-gpios and chip_en.
42+
*/
43+
np = of_find_matching_node_and_match(NULL, wilc_default_pins_ids,
44+
&of_id);
45+
if (np)
46+
gpios = of_id->data;
47+
48+
power->gpios.reset = of_get_named_gpio_flags(of, "reset-gpios", 0,
49+
NULL);
50+
if (!gpio_is_valid(power->gpios.reset) && np)
51+
power->gpios.reset = gpios->reset;
52+
else
53+
goto put_node;
54+
55+
power->gpios.chip_en = of_get_named_gpio_flags(of, "chip_en-gpios", 0,
56+
NULL);
57+
if (!gpio_is_valid(power->gpios.chip_en) && np)
58+
power->gpios.chip_en = gpios->chip_en;
59+
else
60+
goto put_node;
61+
62+
ret = devm_gpio_request(wilc->dev, power->gpios.chip_en, "CHIP_EN");
63+
if (ret)
64+
goto put_node;
65+
66+
ret = devm_gpio_request(wilc->dev, power->gpios.reset, "RESET");
67+
if (ret)
68+
goto put_node;
69+
70+
return 0;
71+
72+
put_node:
73+
of_node_put(np);
74+
return ret;
75+
}
76+
77+
/**
78+
* wilc_wlan_power() - handle power on/off commands
79+
*
80+
* @wilc: wilc data structure
81+
* @on: requested power status
82+
*
83+
* Returns: none
84+
*/
85+
void wilc_wlan_power(struct wilc *wilc, bool on)
86+
{
87+
if (!gpio_is_valid(wilc->power.gpios.chip_en) ||
88+
!gpio_is_valid(wilc->power.gpios.reset)) {
89+
/* In case SDIO power sequence driver is used to power this
90+
* device then the powering sequence is handled by the bus
91+
* via pm_runtime_* functions. */
92+
return;
93+
}
94+
95+
if (on) {
96+
gpio_direction_output(wilc->power.gpios.chip_en, 1);
97+
mdelay(5);
98+
gpio_direction_output(wilc->power.gpios.reset, 1);
99+
} else {
100+
gpio_direction_output(wilc->power.gpios.chip_en, 0);
101+
gpio_direction_output(wilc->power.gpios.reset, 0);
102+
}
103+
}

drivers/staging/wilc1000/sdio.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ static int wilc_sdio_probe(struct sdio_func *func,
149149
int ret, io_type;
150150
static bool init_power;
151151
struct wilc_sdio *sdio_priv;
152+
struct device_node *np;
152153
int irq_num;
153154

154155
sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL);
@@ -183,17 +184,40 @@ static int wilc_sdio_probe(struct sdio_func *func,
183184
clk_prepare_enable(wilc->rtc_clk);
184185
}
185186

186-
if (!init_power) {
187-
ret = wilc_wlan_power_on_sequence(wilc);
187+
/*
188+
* Some WILC SDIO setups needs a SD power sequence driver to be able
189+
* to power the WILC devices before reaching this function. For those
190+
* devices the power sequence driver already provides reset-gpios
191+
* and chip_en-gpios.
192+
*/
193+
np = of_parse_phandle(func->card->host->parent->of_node, "mmc-pwrseq",
194+
0);
195+
if (!np) {
196+
ret = wilc_of_parse_power_pins(wilc);
188197
if (ret)
189-
goto dispose_irq;
198+
goto disable_rtc_clk;
199+
} else {
200+
init_power = 1;
201+
of_node_put(np);
202+
}
203+
204+
205+
if (!init_power) {
206+
/* This could be removed and let hif_init do its job. Also
207+
* doing insert/remove module for many times should lead
208+
* to calling this only the 1st time. */
209+
wilc_wlan_power(wilc, true);
190210
init_power = 1;
191211
}
192212

193213
wilc_bt_init(wilc);
194214

195215
dev_info(&func->dev, "Driver Initializing success\n");
196216
return 0;
217+
218+
disable_rtc_clk:
219+
if (!IS_ERR(wilc->rtc_clk))
220+
clk_disable_unprepare(wilc->rtc_clk);
197221
dispose_irq:
198222
irq_dispose_mapping(wilc->dev_irq_num);
199223
wilc_netdev_cleanup(wilc);
@@ -635,10 +659,14 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
635659

636660
static int wilc_sdio_deinit(struct wilc *wilc)
637661
{
662+
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
638663
struct wilc_sdio *sdio_priv = wilc->bus_data;
639664

640665
sdio_priv->is_init = false;
641666

667+
pm_runtime_put_sync_autosuspend(mmc_dev(func->card->host));
668+
wilc_wlan_power(wilc, false);
669+
642670
return 0;
643671
}
644672

0 commit comments

Comments
 (0)