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>
23 #include <linux/gta02-shadow.h>
25 #include <mach/gta02.h>
26 #include <linux/mfd/pcf50633/gpio.h>
28 #include <linux/regulator/consumer.h>
30 #define DRVMSG "Openmoko Freerunner Bluetooth Power Management"
32 struct gta02_pm_bt_data
{
33 struct regulator
*regulator
;
34 struct rfkill
*rfkill
;
38 static ssize_t
bt_read(struct device
*dev
, struct device_attribute
*attr
,
42 if (!strcmp(attr
->attr
.name
, "power_on")) {
43 if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN
))
45 } else if (!strcmp(attr
->attr
.name
, "reset")) {
46 if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN
) == 0)
51 return strlcpy(buf
, "0\n", 3);
53 return strlcpy(buf
, "1\n", 3);
57 static void __gta02_pm_bt_toggle_radio(struct device
*dev
, unsigned int on
)
59 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(dev
);
61 dev_info(dev
, "__gta02_pm_bt_toggle_radio %d\n", on
);
63 bt_data
= dev_get_drvdata(dev
);
65 gta02_gpb_setpin(GTA02_GPIO_BT_EN
, !on
);
68 if (!regulator_is_enabled(bt_data
->regulator
))
69 regulator_enable(bt_data
->regulator
);
71 if (regulator_is_enabled(bt_data
->regulator
))
72 regulator_disable(bt_data
->regulator
);
75 gta02_gpb_setpin(GTA02_GPIO_BT_EN
, on
);
79 static int bt_rfkill_toggle_radio(void *data
, enum rfkill_state state
)
81 struct device
*dev
= data
;
82 unsigned long on
= (state
== RFKILL_STATE_ON
);
84 __gta02_pm_bt_toggle_radio(dev
, on
);
89 static ssize_t
bt_write(struct device
*dev
, struct device_attribute
*attr
,
90 const char *buf
, size_t count
)
92 unsigned long on
= simple_strtoul(buf
, NULL
, 10);
93 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(dev
);
95 if (!strcmp(attr
->attr
.name
, "power_on")) {
96 enum rfkill_state state
= on
? RFKILL_STATE_ON
: RFKILL_STATE_OFF
;
97 bt_rfkill_toggle_radio(dev
, state
);
98 bt_data
->rfkill
->state
= state
;
100 __gta02_pm_bt_toggle_radio(dev
, on
);
101 } else if (!strcmp(attr
->attr
.name
, "reset")) {
102 /* reset is low-active, so we need to invert */
103 gta02_gpb_setpin(GTA02_GPIO_BT_EN
, on
? 0 : 1);
109 static DEVICE_ATTR(power_on
, 0644, bt_read
, bt_write
);
110 static DEVICE_ATTR(reset
, 0644, bt_read
, bt_write
);
113 static int gta02_bt_suspend(struct platform_device
*pdev
, pm_message_t state
)
115 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(&pdev
->dev
);
117 dev_dbg(&pdev
->dev
, DRVMSG
": suspending\n");
119 bt_data
->pre_resume_state
= s3c2410_gpio_getpin(GTA02_GPIO_BT_EN
);
120 __gta02_pm_bt_toggle_radio(&pdev
->dev
, 0);
125 static int gta02_bt_resume(struct platform_device
*pdev
)
127 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(&pdev
->dev
);
128 dev_dbg(&pdev
->dev
, DRVMSG
": resuming\n");
130 __gta02_pm_bt_toggle_radio(&pdev
->dev
, bt_data
->pre_resume_state
);
134 #define gta02_bt_suspend NULL
135 #define gta02_bt_resume NULL
138 static struct attribute
*gta02_bt_sysfs_entries
[] = {
139 &dev_attr_power_on
.attr
,
140 &dev_attr_reset
.attr
,
144 static struct attribute_group gta02_bt_attr_group
= {
146 .attrs
= gta02_bt_sysfs_entries
,
149 static int __init
gta02_bt_probe(struct platform_device
*pdev
)
151 struct rfkill
*rfkill
;
152 struct regulator
*regulator
;
153 struct gta02_pm_bt_data
*bt_data
;
156 dev_info(&pdev
->dev
, DRVMSG
": starting\n");
158 bt_data
= kzalloc(sizeof(*bt_data
), GFP_KERNEL
);
159 dev_set_drvdata(&pdev
->dev
, bt_data
);
161 regulator
= regulator_get(&pdev
->dev
, "BT_3V2");
162 if (IS_ERR(regulator
))
165 bt_data
->regulator
= regulator
;
167 /* this tests the true physical state of the regulator... */
168 if (regulator_is_enabled(regulator
)) {
170 * but these only operate on the logical state of the
171 * regulator... so we need to logicaly "adopt" it on
174 regulator_enable(regulator
);
175 regulator_disable(regulator
);
178 /* we pull reset to low to make sure that the chip doesn't
179 * drain power through the reset line */
180 gta02_gpb_setpin(GTA02_GPIO_BT_EN
, 0);
182 rfkill
= rfkill_allocate(&pdev
->dev
, RFKILL_TYPE_BLUETOOTH
);
184 rfkill
->name
= pdev
->name
;
185 rfkill
->data
= &pdev
->dev
;
186 rfkill
->state
= RFKILL_STATE_OFF
;
187 rfkill
->toggle_radio
= bt_rfkill_toggle_radio
;
189 ret
= rfkill_register(rfkill
);
191 dev_err(&pdev
->dev
, "Failed to register rfkill\n");
195 bt_data
->rfkill
= rfkill
;
197 return sysfs_create_group(&pdev
->dev
.kobj
, >a02_bt_attr_group
);
200 static int gta02_bt_remove(struct platform_device
*pdev
)
202 struct gta02_pm_bt_data
*bt_data
= dev_get_drvdata(&pdev
->dev
);
203 struct regulator
*regulator
;
205 sysfs_remove_group(&pdev
->dev
.kobj
, >a02_bt_attr_group
);
207 if (bt_data
->rfkill
) {
208 rfkill_unregister(bt_data
->rfkill
);
209 rfkill_free(bt_data
->rfkill
);
212 if (!bt_data
|| !bt_data
->regulator
)
215 regulator
= bt_data
->regulator
;
217 /* Make sure regulator is disabled before calling regulator_put */
218 if (regulator_is_enabled(regulator
))
219 regulator_disable(regulator
);
221 regulator_put(regulator
);
228 static struct platform_driver gta02_bt_driver
= {
229 .probe
= gta02_bt_probe
,
230 .remove
= gta02_bt_remove
,
231 .suspend
= gta02_bt_suspend
,
232 .resume
= gta02_bt_resume
,
234 .name
= "gta02-pm-bt",
238 static int __devinit
gta02_bt_init(void)
240 return platform_driver_register(>a02_bt_driver
);
243 static void gta02_bt_exit(void)
245 platform_driver_unregister(>a02_bt_driver
);
248 module_init(gta02_bt_init
);
249 module_exit(gta02_bt_exit
);
251 MODULE_LICENSE("GPL");
252 MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
253 MODULE_DESCRIPTION(DRVMSG
);