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 d119a7c..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>
 
  */
 #define MCU_REG_CTRL   0x20
 #define MCU_CTRL_POFF  0x40
+#define MCU_CTRL_BTN   0x80
 
 #define MCU_NUM_GPIO   2
 
 struct mcu {
        struct mutex lock;
-       struct device_node *np;
        struct i2c_client *client;
-       struct of_gpio_chip of_gc;
+       struct gpio_chip gc;
        u8 reg_ctrl;
 };
 
 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);
 }
 
 static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-       struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
-       struct mcu *mcu = container_of(of_gc, struct mcu, of_gc);
+       struct mcu *mcu = container_of(gc, struct mcu, gc);
        u8 bit = 1 << (4 + gpio);
 
        mutex_lock(&mcu->lock);
@@ -79,9 +122,7 @@ static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 static int mcu_gpiochip_add(struct mcu *mcu)
 {
        struct device_node *np;
-       struct of_gpio_chip *of_gc = &mcu->of_gc;
-       struct gpio_chip *gc = &of_gc->gc;
-       int ret;
+       struct gpio_chip *gc = &mcu->gc;
 
        np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx");
        if (!np)
@@ -94,32 +135,14 @@ static int mcu_gpiochip_add(struct mcu *mcu)
        gc->base = -1;
        gc->set = mcu_gpio_set;
        gc->direction_output = mcu_gpio_dir_out;
-       of_gc->gpio_cells = 2;
-       of_gc->xlate = of_gpio_simple_xlate;
+       gc->of_node = np;
 
-       np->data = of_gc;
-       mcu->np = np;
-
-       /*
-        * We don't want to lose the node, its ->data and ->full_name...
-        * So, if succeeded, we don't put the node here.
-        */
-       ret = gpiochip_add(gc);
-       if (ret)
-               of_node_put(np);
-       return ret;
+       return gpiochip_add(gc);
 }
 
 static int mcu_gpiochip_remove(struct mcu *mcu)
 {
-       int ret;
-
-       ret = gpiochip_remove(&mcu->of_gc.gc);
-       if (ret)
-               return ret;
-       of_node_put(mcu->np);
-
-       return 0;
+       return gpiochip_remove(&mcu->gc);
 }
 
 static int __devinit mcu_probe(struct i2c_client *client,
@@ -152,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);
@@ -163,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;
@@ -182,10 +216,16 @@ static const struct i2c_device_id mcu_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mcu_ids);
 
+static struct of_device_id mcu_of_match_table[] __devinitdata = {
+       { .compatible = "fsl,mcu-mpc8349emitx", },
+       { },
+};
+
 static struct i2c_driver mcu_driver = {
        .driver = {
                .name = "mcu-mpc8349emitx",
                .owner = THIS_MODULE,
+               .of_match_table = mcu_of_match_table,
        },
        .probe = mcu_probe,
        .remove = __devexit_p(mcu_remove),