2 * Bluetooth PM code for the Openmoko Freerunner GSM Phone
4 * (C) 2007 by Openmoko Inc.
5 * Author: Harald Welte <laforge@openmoko.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/platform_device.h>
18 #include <linux/rfkill.h>
19 #include <linux/err.h>
21 #include <mach/hardware.h>
22 #include <asm/mach-types.h>
24 #include <mach/gta02.h>
25 #include <linux/mfd/pcf50633/gpio.h>
27 #include <linux/regulator/consumer.h>
29 #define DRVMSG "Openmoko Freerunner Bluetooth Power Management"
31 struct gta02_pm_bt_data
{
32 struct regulator
*regulator
;
33 struct rfkill
*rfkill
;
37 static ssize_t
bt_read(struct device
*dev
, struct device_attribute
*attr
,
41 if (!strcmp(attr
->attr
.name
, "power_on")) {
42 if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN
))
44 } else if (!strcmp(attr
->attr
.name
, "reset")) {
45 if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN
) == 0)
50 return strlcpy(buf
, "0\n", 3);
52 return strlcpy(buf
, "1\n", 3);
56 static void __gta02_pm_bt_toggle_radio(struct device
*dev
, unsigned int on
)
58 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(dev
);
60 dev_info(dev
, "__gta02_pm_bt_toggle_radio %d\n", on
);
62 bt_data
= dev_get_drvdata(dev
);
64 s3c2410_gpio_setpin(GTA02_GPIO_BT_EN
, !on
);
67 if (!regulator_is_enabled(bt_data
->regulator
))
68 regulator_enable(bt_data
->regulator
);
70 if (regulator_is_enabled(bt_data
->regulator
))
71 regulator_disable(bt_data
->regulator
);
74 s3c2410_gpio_setpin(GTA02_GPIO_BT_EN
, on
);
78 static int bt_rfkill_toggle_radio(void *data
, enum rfkill_state state
)
80 struct device
*dev
= data
;
81 unsigned long on
= (state
== RFKILL_STATE_ON
);
83 __gta02_pm_bt_toggle_radio(dev
, on
);
88 static ssize_t
bt_write(struct device
*dev
, struct device_attribute
*attr
,
89 const char *buf
, size_t count
)
91 unsigned long on
= simple_strtoul(buf
, NULL
, 10);
92 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(dev
);
94 if (!strcmp(attr
->attr
.name
, "power_on")) {
95 enum rfkill_state state
= on
? RFKILL_STATE_ON
: RFKILL_STATE_OFF
;
96 bt_rfkill_toggle_radio(dev
, state
);
97 bt_data
->rfkill
->state
= state
;
99 __gta02_pm_bt_toggle_radio(dev
, on
);
100 } else if (!strcmp(attr
->attr
.name
, "reset")) {
101 /* reset is low-active, so we need to invert */
102 s3c2410_gpio_setpin(GTA02_GPIO_BT_EN
, on
? 0 : 1);
108 static DEVICE_ATTR(power_on
, 0644, bt_read
, bt_write
);
109 static DEVICE_ATTR(reset
, 0644, bt_read
, bt_write
);
112 static int gta02_bt_suspend(struct platform_device
*pdev
, pm_message_t state
)
114 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(&pdev
->dev
);
116 dev_dbg(&pdev
->dev
, DRVMSG
": suspending\n");
118 bt_data
->pre_resume_state
= s3c2410_gpio_getpin(GTA02_GPIO_BT_EN
);
119 __gta02_pm_bt_toggle_radio(&pdev
->dev
, 0);
124 static int gta02_bt_resume(struct platform_device
*pdev
)
126 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(&pdev
->dev
);
127 dev_dbg(&pdev
->dev
, DRVMSG
": resuming\n");
129 __gta02_pm_bt_toggle_radio(&pdev
->dev
, bt_data
->pre_resume_state
);
133 #define gta02_bt_suspend NULL
134 #define gta02_bt_resume NULL
137 static struct attribute
*gta02_bt_sysfs_entries
[] = {
138 &dev_attr_power_on
.attr
,
139 &dev_attr_reset
.attr
,
143 static struct attribute_group gta02_bt_attr_group
= {
145 .attrs
= gta02_bt_sysfs_entries
,
148 static int __init
gta02_bt_probe(struct platform_device
*pdev
)
150 struct rfkill
*rfkill
;
151 struct regulator
*regulator
;
152 struct gta02_pm_bt_data
*bt_data
;
155 dev_info(&pdev
->dev
, DRVMSG
": starting\n");
157 bt_data
= kzalloc(sizeof(*bt_data
), GFP_KERNEL
);
158 dev_set_drvdata(&pdev
->dev
, bt_data
);
160 regulator
= regulator_get(&pdev
->dev
, "BT_3V2");
161 if (IS_ERR(regulator
))
164 bt_data
->regulator
= regulator
;
166 /* this tests the true physical state of the regulator... */
167 if (regulator_is_enabled(regulator
)) {
169 * but these only operate on the logical state of the
170 * regulator... so we need to logicaly "adopt" it on
173 regulator_enable(regulator
);
174 regulator_disable(regulator
);
177 /* we pull reset to low to make sure that the chip doesn't
178 * drain power through the reset line */
179 s3c2410_gpio_setpin(GTA02_GPIO_BT_EN
, 0);
181 rfkill
= rfkill_allocate(&pdev
->dev
, RFKILL_TYPE_BLUETOOTH
);
183 rfkill
->name
= pdev
->name
;
184 rfkill
->data
= &pdev
->dev
;
185 rfkill
->state
= RFKILL_STATE_OFF
;
186 rfkill
->toggle_radio
= bt_rfkill_toggle_radio
;
188 ret
= rfkill_register(rfkill
);
190 dev_err(&pdev
->dev
, "Failed to register rfkill\n");
194 bt_data
->rfkill
= rfkill
;
196 return sysfs_create_group(&pdev
->dev
.kobj
, >a02_bt_attr_group
);
199 static int gta02_bt_remove(struct platform_device
*pdev
)
201 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(&pdev
->dev
);
202 struct regulator
*regulator
;
204 sysfs_remove_group(&pdev
->dev
.kobj
, >a02_bt_attr_group
);
206 if (bt_data
->rfkill
) {
207 rfkill_unregister(bt_data
->rfkill
);
208 rfkill_free(bt_data
->rfkill
);
211 if (!bt_data
|| !bt_data
->regulator
)
214 regulator
= bt_data
->regulator
;
216 /* Make sure regulator is disabled before calling regulator_put */
217 if (regulator_is_enabled(regulator
))
218 regulator_disable(regulator
);
220 regulator_put(regulator
);
227 static struct platform_driver gta02_bt_driver
= {
228 .probe
= gta02_bt_probe
,
229 .remove
= gta02_bt_remove
,
230 .suspend
= gta02_bt_suspend
,
231 .resume
= gta02_bt_resume
,
233 .name
= "gta02-pm-bt",
237 static int __devinit
gta02_bt_init(void)
239 return platform_driver_register(>a02_bt_driver
);
242 static void gta02_bt_exit(void)
244 platform_driver_unregister(>a02_bt_driver
);
247 module_init(gta02_bt_init
);
248 module_exit(gta02_bt_exit
);
250 MODULE_LICENSE("GPL");
251 MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
252 MODULE_DESCRIPTION(DRVMSG
);