Merge branch 'dev' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[pandora-kernel.git] / arch / powerpc / platforms / 83xx / mcu_mpc8349emitx.c
index 70798ac..ef6537b 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/reboot.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 
@@ -30,6 +32,7 @@
  */
 #define MCU_REG_CTRL   0x20
 #define MCU_CTRL_POFF  0x40
+#define MCU_CTRL_BTN   0x80
 
 #define MCU_NUM_GPIO   2
 
@@ -42,13 +45,55 @@ struct mcu {
 
 static struct mcu *glob_mcu;
 
+struct task_struct *shutdown_thread;
+static int shutdown_thread_fn(void *data)
+{
+       int ret;
+       struct mcu *mcu = glob_mcu;
+
+       while (!kthread_should_stop()) {
+               ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
+               if (ret < 0)
+                       pr_err("MCU status reg read failed.\n");
+               mcu->reg_ctrl = ret;
+
+
+               if (mcu->reg_ctrl & MCU_CTRL_BTN) {
+                       i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL,
+                                                 mcu->reg_ctrl & ~MCU_CTRL_BTN);
+
+                       ctrl_alt_del();
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ);
+       }
+
+       return 0;
+}
+
+static ssize_t show_status(struct device *d,
+                          struct device_attribute *attr, char *buf)
+{
+       int ret;
+       struct mcu *mcu = glob_mcu;
+
+       ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
+       if (ret < 0)
+               return -ENODEV;
+       mcu->reg_ctrl = ret;
+
+       return sprintf(buf, "%02x\n", ret);
+}
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
 static void mcu_power_off(void)
 {
        struct mcu *mcu = glob_mcu;
 
        pr_info("Sending power-off request to the MCU...\n");
        mutex_lock(&mcu->lock);
-       i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL,
+       i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL,
                                  mcu->reg_ctrl | MCU_CTRL_POFF);
        mutex_unlock(&mcu->lock);
 }
@@ -130,6 +175,13 @@ static int __devinit mcu_probe(struct i2c_client *client,
                dev_info(&client->dev, "will provide power-off service\n");
        }
 
+       if (device_create_file(&client->dev, &dev_attr_status))
+               dev_err(&client->dev,
+                       "couldn't create device file for status\n");
+
+       shutdown_thread = kthread_run(shutdown_thread_fn, NULL,
+                                     "mcu-i2c-shdn");
+
        return 0;
 err:
        kfree(mcu);
@@ -141,6 +193,10 @@ static int __devexit mcu_remove(struct i2c_client *client)
        struct mcu *mcu = i2c_get_clientdata(client);
        int ret;
 
+       kthread_stop(shutdown_thread);
+
+       device_remove_file(&client->dev, &dev_attr_status);
+
        if (glob_mcu == mcu) {
                ppc_md.power_off = NULL;
                glob_mcu = NULL;