diff options
author | Fabio Baltieri <fabio.baltieri@gmail.com> | 2011-08-15 10:19:30 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2011-11-03 14:12:30 -0400 |
commit | 6ca6ca5d813845533bcaaaeb2ca59d0805a028ca (patch) | |
tree | c5dbff975e963e54ef2203187c8e89b5f26bf5d4 /arch/powerpc/platforms/83xx | |
parent | 43a327b79c3945049ccf675452d2d519084c9bc6 (diff) |
powerpc/83xx: Add shutdown request support to MCU handling on MPC8349 MITX
This patch add support for calling ctrl_alt_del() when the power button is
pressed for more than about 2 seconds on some freescale MPC83xx evaluation
boards and reference design.
The code uses a kthread to poll the CTRL_BTN bit each second.
Also change Kconfig entry of the driver to bool, as device's gpio
registration is broken when loading as module.
Tested on an MPC8315E RDB board.
Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/83xx')
-rw-r--r-- | arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index 70798ac911ef..ef6537b8ed33 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_gpio.h> | 22 | #include <linux/of_gpio.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/kthread.h> | ||
25 | #include <linux/reboot.h> | ||
24 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
25 | #include <asm/machdep.h> | 27 | #include <asm/machdep.h> |
26 | 28 | ||
@@ -30,6 +32,7 @@ | |||
30 | */ | 32 | */ |
31 | #define MCU_REG_CTRL 0x20 | 33 | #define MCU_REG_CTRL 0x20 |
32 | #define MCU_CTRL_POFF 0x40 | 34 | #define MCU_CTRL_POFF 0x40 |
35 | #define MCU_CTRL_BTN 0x80 | ||
33 | 36 | ||
34 | #define MCU_NUM_GPIO 2 | 37 | #define MCU_NUM_GPIO 2 |
35 | 38 | ||
@@ -42,13 +45,55 @@ struct mcu { | |||
42 | 45 | ||
43 | static struct mcu *glob_mcu; | 46 | static struct mcu *glob_mcu; |
44 | 47 | ||
48 | struct task_struct *shutdown_thread; | ||
49 | static int shutdown_thread_fn(void *data) | ||
50 | { | ||
51 | int ret; | ||
52 | struct mcu *mcu = glob_mcu; | ||
53 | |||
54 | while (!kthread_should_stop()) { | ||
55 | ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL); | ||
56 | if (ret < 0) | ||
57 | pr_err("MCU status reg read failed.\n"); | ||
58 | mcu->reg_ctrl = ret; | ||
59 | |||
60 | |||
61 | if (mcu->reg_ctrl & MCU_CTRL_BTN) { | ||
62 | i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, | ||
63 | mcu->reg_ctrl & ~MCU_CTRL_BTN); | ||
64 | |||
65 | ctrl_alt_del(); | ||
66 | } | ||
67 | |||
68 | set_current_state(TASK_INTERRUPTIBLE); | ||
69 | schedule_timeout(HZ); | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static ssize_t show_status(struct device *d, | ||
76 | struct device_attribute *attr, char *buf) | ||
77 | { | ||
78 | int ret; | ||
79 | struct mcu *mcu = glob_mcu; | ||
80 | |||
81 | ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL); | ||
82 | if (ret < 0) | ||
83 | return -ENODEV; | ||
84 | mcu->reg_ctrl = ret; | ||
85 | |||
86 | return sprintf(buf, "%02x\n", ret); | ||
87 | } | ||
88 | static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); | ||
89 | |||
45 | static void mcu_power_off(void) | 90 | static void mcu_power_off(void) |
46 | { | 91 | { |
47 | struct mcu *mcu = glob_mcu; | 92 | struct mcu *mcu = glob_mcu; |
48 | 93 | ||
49 | pr_info("Sending power-off request to the MCU...\n"); | 94 | pr_info("Sending power-off request to the MCU...\n"); |
50 | mutex_lock(&mcu->lock); | 95 | mutex_lock(&mcu->lock); |
51 | i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL, | 96 | i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, |
52 | mcu->reg_ctrl | MCU_CTRL_POFF); | 97 | mcu->reg_ctrl | MCU_CTRL_POFF); |
53 | mutex_unlock(&mcu->lock); | 98 | mutex_unlock(&mcu->lock); |
54 | } | 99 | } |
@@ -130,6 +175,13 @@ static int __devinit mcu_probe(struct i2c_client *client, | |||
130 | dev_info(&client->dev, "will provide power-off service\n"); | 175 | dev_info(&client->dev, "will provide power-off service\n"); |
131 | } | 176 | } |
132 | 177 | ||
178 | if (device_create_file(&client->dev, &dev_attr_status)) | ||
179 | dev_err(&client->dev, | ||
180 | "couldn't create device file for status\n"); | ||
181 | |||
182 | shutdown_thread = kthread_run(shutdown_thread_fn, NULL, | ||
183 | "mcu-i2c-shdn"); | ||
184 | |||
133 | return 0; | 185 | return 0; |
134 | err: | 186 | err: |
135 | kfree(mcu); | 187 | kfree(mcu); |
@@ -141,6 +193,10 @@ static int __devexit mcu_remove(struct i2c_client *client) | |||
141 | struct mcu *mcu = i2c_get_clientdata(client); | 193 | struct mcu *mcu = i2c_get_clientdata(client); |
142 | int ret; | 194 | int ret; |
143 | 195 | ||
196 | kthread_stop(shutdown_thread); | ||
197 | |||
198 | device_remove_file(&client->dev, &dev_attr_status); | ||
199 | |||
144 | if (glob_mcu == mcu) { | 200 | if (glob_mcu == mcu) { |
145 | ppc_md.power_off = NULL; | 201 | ppc_md.power_off = NULL; |
146 | glob_mcu = NULL; | 202 | glob_mcu = NULL; |