This patch create a new platform driver which adds support for RF kill to the on-board WM-G-MR-09 wifi chip. It also adds the platform device glue to the SmartQ board definitions. Signed-off-by: Maurus Cuelenaere <mcuelenaere@xxxxxxxxx> --- arch/arm/mach-s3c64xx/Kconfig | 7 ++ arch/arm/mach-s3c64xx/Makefile | 3 + arch/arm/mach-s3c64xx/mach-smartq.c | 38 ++-------- arch/arm/mach-s3c64xx/smartq-wifi.c | 135 +++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 31 deletions(-) create mode 100644 arch/arm/mach-s3c64xx/smartq-wifi.c diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 071e8a1..42a8c45 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -234,3 +234,10 @@ config MACH_SMARTQ7 select MACH_SMARTQ help Machine support for the SmartQ 7 + +config SMARTQ_WIFI + bool + default y + depends on MACH_SMARTQ && (RFKILL || !RFKILL) + help + RF kill support for SmartQ wifi chip diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 48d3dfa..46af002 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -65,3 +65,6 @@ obj-y += dev-audio.o obj-$(CONFIG_S3C64XX_DEV_SPI) += dev-spi.o obj-$(CONFIG_S3C64XX_DEV_TS) += dev-ts.o obj-$(CONFIG_S3C64XX_DEV_ONENAND1) += dev-onenand1.o + +# Misc +obj-$(CONFIG_SMARTQ_WIFI) += smartq-wifi.o diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c index 3a9639b..0e3f43d 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq.c +++ b/arch/arm/mach-s3c64xx/mach-smartq.c @@ -9,7 +9,6 @@ * */ -#include <linux/delay.h> #include <linux/fb.h> #include <linux/gpio.h> #include <linux/init.h> @@ -231,6 +230,12 @@ static struct i2c_board_info smartq_i2c_devs[] __initdata = { { I2C_BOARD_INFO("wm8987", 0x1a), }, }; +static struct platform_device smartq_wifi_device = { + .name = "smartq-wifi", + .id = -1, + .dev.parent = &s3c_device_hsmmc2.dev, +}; + static struct platform_device *smartq_devices[] __initdata = { &s3c_device_hsmmc1, /* Init iNAND first, ... */ &s3c_device_hsmmc0, /* ... then the external SD card */ @@ -249,6 +254,7 @@ static struct platform_device *smartq_devices[] __initdata = { &smartq_lcd_control_device, &smartq_lcd_power_device, &smartq_usb_otg_vbus_dev, + &smartq_wifi_device, }; static void __init smartq_lcd_mode_set(void) @@ -339,35 +345,6 @@ static int __init smartq_usb_otg_init(void) return 0; } -static int __init smartq_wifi_init(void) -{ - int ret; - - ret = gpio_request(S3C64XX_GPK(1), "wifi control"); - if (ret < 0) { - pr_err("%s: failed to get GPK1\n", __func__); - return ret; - } - - ret = gpio_request(S3C64XX_GPK(2), "wifi reset"); - if (ret < 0) { - pr_err("%s: failed to get GPK2\n", __func__); - gpio_free(S3C64XX_GPK(1)); - return ret; - } - - /* turn power on */ - gpio_direction_output(S3C64XX_GPK(1), 1); - - /* reset device */ - gpio_direction_output(S3C64XX_GPK(2), 0); - mdelay(100); - gpio_set_value(S3C64XX_GPK(2), 1); - gpio_direction_input(S3C64XX_GPK(2)); - - return 0; -} - static struct map_desc smartq_iodesc[] __initdata = {}; void __init smartq_map_io(void) { @@ -393,7 +370,6 @@ void __init smartq_machine_init(void) WARN_ON(smartq_power_off_init()); WARN_ON(smartq_usb_host_init()); WARN_ON(smartq_usb_otg_init()); - WARN_ON(smartq_wifi_init()); platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices)); } diff --git a/arch/arm/mach-s3c64xx/smartq-wifi.c b/arch/arm/mach-s3c64xx/smartq-wifi.c new file mode 100644 index 0000000..54b2406 --- /dev/null +++ b/arch/arm/mach-s3c64xx/smartq-wifi.c @@ -0,0 +1,135 @@ +/* + * linux/arch/arm/mach-s3c64xx/smartq-rfkill.c + * + * Copyright (C) 2010 Maurus Cuelenaere + * Based on h1940 bluetooth RF kill driver + * Copyright (c) Arnaud Patard <arnaud.patard@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rfkill.h> + +#include <plat/gpio-cfg.h> + +#define WIFI_POWER S3C64XX_GPK(1) +#define WIFI_RESET S3C64XX_GPK(2) + +#define smartq_wifi_enable(en) smartq_wifi_rfk_block(NULL, !en) + +static int smartq_wifi_rfk_block(void *data, bool blocked) +{ + /* change power depending on state */ + gpio_set_value(WIFI_POWER, !blocked); + + if (!blocked) { + /* when powering on, reset device */ + gpio_direction_output(WIFI_RESET, 0); + ndelay(100); /* WM-G-MR-09 product spec, + 6.2.5 RESET AND CONFIGURATION TIMING */ + gpio_set_value(WIFI_RESET, 1); + } + gpio_direction_input(WIFI_RESET); + + return 0; +} + +static const struct rfkill_ops smartq_wifi_rfk_ops = { + .set_block = smartq_wifi_rfk_block, +}; + +static int __devinit smartq_wifi_probe(struct platform_device *pdev) +{ + struct rfkill *rfk; + int ret; + + ret = gpio_request(WIFI_POWER, "wifi control"); + if (ret < 0) { + pr_err("%s: failed to get GPK1\n", __func__); + return ret; + } + gpio_direction_output(WIFI_POWER, 0); + + ret = gpio_request(WIFI_RESET, "wifi reset"); + if (ret < 0) { + pr_err("%s: failed to get GPK2\n", __func__); + goto err_wifi_control; + } + gpio_direction_input(WIFI_RESET); + + rfk = rfkill_alloc("smartq-wlan", &pdev->dev, RFKILL_TYPE_WLAN, + &smartq_wifi_rfk_ops, NULL); + + if (!rfk) { + ret = -ENOMEM; + goto err_rfk_alloc; + } + + rfkill_set_led_trigger_name(rfk, "smartq-wlan"); + + ret = rfkill_register(rfk); + if (ret) + goto err_rfk; + + platform_set_drvdata(pdev, rfk); + + return 0; + +err_rfk: + rfkill_destroy(rfk); +err_rfk_alloc: + gpio_free(S3C64XX_GPK(2)); +err_wifi_control: + gpio_free(S3C64XX_GPK(1)); + return ret; +} + +static int smartq_wifi_remove(struct platform_device *pdev) +{ + struct rfkill *rfk = platform_get_drvdata(pdev); + + smartq_wifi_enable(false); + + if (rfk) { + rfkill_unregister(rfk); + rfkill_destroy(rfk); + } + + platform_set_drvdata(pdev, NULL); + gpio_free(WIFI_POWER); + gpio_free(WIFI_RESET); + + return 0; +} + +static struct platform_driver smartq_wifi_driver = { + .driver = { + .name = "smartq-wifi", + }, + .probe = smartq_wifi_probe, + .remove = smartq_wifi_remove, +}; + +static int __init smartq_wifi_init(void) +{ + return platform_driver_register(&smartq_wifi_driver); +} + +static void __exit smartq_wifi_exit(void) +{ + platform_driver_unregister(&smartq_wifi_driver); +} + +module_init(smartq_wifi_init); +module_exit(smartq_wifi_exit); + +MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>"); +MODULE_DESCRIPTION("SmartQ WiFi RF kill driver"); +MODULE_LICENSE("GPLv2"); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html