summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeung-Woo Kim <sw0312.kim@samsung.com>2014-08-08 17:13:09 +0900
committerChanho Park <chanho61.park@samsung.com>2014-11-18 12:00:33 +0900
commitf9faaa1e7826a562227b6d44635b65d47a7b3042 (patch)
tree674062809c60b8c28e5a5a083257d9a582b7e092
parent774dab1751b19d4315ce8b94895fe84d6aee9c5f (diff)
downloadlinux-3.10-f9faaa1e7826a562227b6d44635b65d47a7b3042.tar.gz
linux-3.10-f9faaa1e7826a562227b6d44635b65d47a7b3042.tar.bz2
linux-3.10-f9faaa1e7826a562227b6d44635b65d47a7b3042.zip
net: rfkill-gpio: add host wake and wake pins
WORKAROUND: Temporary workaround for bluetooth enable. The wake pin is used for waking up the hw and host wake pin is used for waking up host processor during sleep. Additionally, This patch add reset-gpio property and devm_gpio_request_one function. Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com> [This patch rebased by Beomho Seo] Signed-off-by: Beomho Seo <beomho.seo@samsung.com> Change-Id: Ibb2f74cae6e1d11ae84172d0f49a10563fc57e7f
-rw-r--r--include/linux/rfkill-gpio.h4
-rw-r--r--net/rfkill/rfkill-gpio.c99
2 files changed, 103 insertions, 0 deletions
diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
index 4d09f6eab35..64624ba6f49 100644
--- a/include/linux/rfkill-gpio.h
+++ b/include/linux/rfkill-gpio.h
@@ -29,6 +29,8 @@
* @name: name for the gpio rf kill instance
* @reset_gpio: GPIO which is used for reseting rfkill switch
* @shutdown_gpio: GPIO which is used for shutdown of rfkill switch
+ * @wake_gpio: GPIO which is used for wake of rfkill switch
+ * @host_wake_gpio: GPIO which is used for wake of host from rfkill switch
* @power_clk_name: [optional] name of clk to turn off while blocked
* @gpio_runtime_close: clean up platform specific gpio configuration
* @gpio_runtime_setup: set up platform specific gpio configuration
@@ -38,6 +40,8 @@ struct rfkill_gpio_platform_data {
char *name;
int reset_gpio;
int shutdown_gpio;
+ int wake_gpio;
+ int host_wake_gpio;
const char *power_clk_name;
enum rfkill_type type;
void (*gpio_runtime_close)(struct platform_device *);
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 212a77f38f2..37f9dc8f7a2 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -27,19 +27,26 @@
#include <linux/of_gpio.h>
#include <linux/rfkill-gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
struct rfkill_gpio_data {
const char *name;
enum rfkill_type type;
int reset_gpio;
int shutdown_gpio;
+ int wake_gpio;
+ int host_wake_gpio;
struct rfkill *rfkill_dev;
char *reset_name;
char *shutdown_name;
+ char *wake_name;
+ char *host_wake_name;
struct clk *clk;
bool clk_enabled;
+ int irq;
};
static int rfkill_gpio_set_power(void *data, bool blocked)
@@ -51,11 +58,15 @@ static int rfkill_gpio_set_power(void *data, bool blocked)
gpio_set_value(rfkill->shutdown_gpio, 0);
if (gpio_is_valid(rfkill->reset_gpio))
gpio_set_value(rfkill->reset_gpio, 0);
+ if (gpio_is_valid(rfkill->wake_gpio))
+ gpio_set_value(rfkill->wake_gpio, 0);
if (!IS_ERR(rfkill->clk) && rfkill->clk_enabled)
clk_disable_unprepare(rfkill->clk);
} else {
if (!IS_ERR(rfkill->clk) && !rfkill->clk_enabled)
clk_prepare_enable(rfkill->clk);
+ if (gpio_is_valid(rfkill->wake_gpio))
+ gpio_set_value(rfkill->wake_gpio, 1);
if (gpio_is_valid(rfkill->reset_gpio))
gpio_set_value(rfkill->reset_gpio, 1);
if (gpio_is_valid(rfkill->shutdown_gpio))
@@ -80,10 +91,28 @@ static int rfkill_gpio_dt_probe(struct device *dev,
of_property_read_string(np, "rfkill-name", &rfkill->name);
of_property_read_u32(np, "rfkill-type", &rfkill->type);
rfkill->shutdown_gpio = of_get_named_gpio(np, "shutdown-gpio", 0);
+ rfkill->wake_gpio = of_get_named_gpio(np, "wake-gpio", 0);
+ rfkill->host_wake_gpio = of_get_named_gpio(np, "host-wake-gpio", 0);
+ rfkill->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+
return 0;
}
+static irqreturn_t rfkill_gpio_irq_handler(int irq, void *data)
+{
+ struct rfkill_gpio_data *rfkill = data;
+ int host_wake;
+ unsigned int type;
+
+ host_wake = gpio_get_value(rfkill->host_wake_gpio);
+ type = (host_wake ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) |
+ IRQF_NO_SUSPEND;
+ irq_set_irq_type(rfkill->irq, type);
+
+ return IRQ_HANDLED;
+}
+
static int rfkill_gpio_probe(struct platform_device *pdev)
{
struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
@@ -158,6 +187,39 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
}
}
+ if (gpio_is_valid(rfkill->wake_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, rfkill->wake_gpio,
+ 0, rfkill->wake_name);
+ if (ret) {
+ pr_warn("%s: failed to get wake gpio.\n", __func__);
+ return ret;
+ }
+ }
+
+ if (gpio_is_valid(rfkill->host_wake_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, rfkill->host_wake_gpio,
+ 1, rfkill->host_wake_name);
+ if (ret) {
+ pr_warn("%s: failed to get host wake gpio.\n",
+ __func__);
+ return ret;
+ }
+
+ rfkill->irq = gpio_to_irq(rfkill->host_wake_gpio);
+ ret = devm_request_irq(&pdev->dev, rfkill->irq,
+ rfkill_gpio_irq_handler,
+ IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
+ "rfkill-gpio-irq", rfkill);
+ if (ret) {
+ pr_warn("%s: failed to request IRQ(%d) ret(%d)\n",
+ __func__, rfkill->irq, ret);
+ return ret;
+ }
+ ret = irq_set_irq_wake(rfkill->irq, 1);
+ if (ret)
+ return ret;
+ }
+
rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev,
rfkill->type, &rfkill_gpio_ops,
rfkill);
@@ -174,6 +236,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill_set_sw_state(rfkill->rfkill_dev, true);
+ device_init_wakeup(&pdev->dev, true);
+
dev_info(&pdev->dev, "%s device registered.\n", rfkill->name);
return 0;
@@ -192,6 +256,40 @@ static int rfkill_gpio_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int rfkill_gpio_suspend(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(rfkill->irq);
+
+ return 0;
+}
+
+static int rfkill_gpio_resume(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rfkill->irq);
+
+ return 0;
+}
+#else
+#define rfkill_gpio_suspend NULL
+#define rfkill_gpio_resume NULL
+#endif /* CONFIG_PM */
+
+const struct dev_pm_ops rfkill_gpio_pm = {
+ .suspend = rfkill_gpio_suspend,
+ .resume = rfkill_gpio_resume,
+};
+
static const struct of_device_id rfkill_of_match[] = {
{ .compatible = "rfkill-gpio", },
{},
@@ -203,6 +301,7 @@ static struct platform_driver rfkill_gpio_driver = {
.driver = {
.name = "rfkill_gpio",
.owner = THIS_MODULE,
+ .pm = &rfkill_gpio_pm,
.of_match_table = of_match_ptr(rfkill_of_match),
},
};