diff options
| -rw-r--r-- | arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 58 | ||||
| -rw-r--r-- | arch/powerpc/platforms/Kconfig | 2 |
2 files changed, 58 insertions, 2 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; |
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 9fdb9b6ab371..e4588721ef34 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
| @@ -346,7 +346,7 @@ config SIMPLE_GPIO | |||
| 346 | on-board peripherals. | 346 | on-board peripherals. |
| 347 | 347 | ||
| 348 | config MCU_MPC8349EMITX | 348 | config MCU_MPC8349EMITX |
| 349 | tristate "MPC8349E-mITX MCU driver" | 349 | bool "MPC8349E-mITX MCU driver" |
| 350 | depends on I2C && PPC_83xx | 350 | depends on I2C && PPC_83xx |
| 351 | select GENERIC_GPIO | 351 | select GENERIC_GPIO |
| 352 | select ARCH_REQUIRE_GPIOLIB | 352 | select ARCH_REQUIRE_GPIOLIB |
