| /* Quanta EC driver for the Winbond Embedded Controller |
| * |
| * Copyright (C) 2009 Quanta Computer Inc. |
| * |
| * This software is licensed under the terms of the GNU General Public |
| * License version 2, as published by the Free Software Foundation, and |
| * may be copied, distributed, and modified under those terms. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/err.h> |
| #include <linux/i2c.h> |
| #include <linux/slab.h> |
| |
| #define EC_ID_NAME "qci-i2cec" |
| #define EC_BUFFER_LEN 16 |
| #define EC_CMD_POWER_OFF 0xAC |
| #define EC_CMD_RESTART 0xAB |
| |
| static struct i2c_client *g_i2cec_client; |
| |
| /* General structure to hold the driver data */ |
| struct i2cec_drv_data { |
| struct i2c_client *i2cec_client; |
| struct work_struct work; |
| char ec_data[EC_BUFFER_LEN+1]; |
| }; |
| |
| static int __devinit wpce_probe(struct i2c_client *client, |
| const struct i2c_device_id *id); |
| static int __devexit wpce_remove(struct i2c_client *kbd); |
| |
| #ifdef CONFIG_PM |
| static int wpce_suspend(struct device *dev) |
| { |
| return 0; |
| } |
| |
| static int wpce_resume(struct device *dev) |
| { |
| return 0; |
| } |
| #endif |
| |
| #ifdef CONFIG_PM |
| static struct dev_pm_ops wpce_pm_ops = { |
| .suspend = wpce_suspend, |
| .resume = wpce_resume, |
| }; |
| #endif |
| |
| static const struct i2c_device_id wpce_idtable[] = { |
| { EC_ID_NAME, 0 }, |
| { } |
| }; |
| |
| static struct i2c_driver wpce_driver = { |
| .driver = { |
| .owner = THIS_MODULE, |
| .name = EC_ID_NAME, |
| #ifdef CONFIG_PM |
| .pm = &wpce_pm_ops, |
| #endif |
| }, |
| .probe = wpce_probe, |
| .remove = __devexit_p(wpce_remove), |
| .id_table = wpce_idtable, |
| }; |
| |
| static int __devinit wpce_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| int err = -ENOMEM; |
| struct i2cec_drv_data *context = 0; |
| |
| /* there is no need to call i2c_check_functionality() since it is the |
| client's job to use the interface (I2C vs SMBUS) appropriate for it. */ |
| client->driver = &wpce_driver; |
| context = kzalloc(sizeof(struct i2cec_drv_data), GFP_KERNEL); |
| if (!context) |
| return err; |
| |
| context->i2cec_client = client; |
| g_i2cec_client = client; |
| i2c_set_clientdata(context->i2cec_client, context); |
| |
| return 0; |
| } |
| |
| static int __devexit wpce_remove(struct i2c_client *dev) |
| { |
| struct i2cec_drv_data *context = i2c_get_clientdata(dev); |
| g_i2cec_client = NULL; |
| kfree(context); |
| |
| return 0; |
| } |
| |
| static int __init wpce_init(void) |
| { |
| return i2c_add_driver(&wpce_driver); |
| } |
| |
| static void __exit wpce_exit(void) |
| { |
| i2c_del_driver(&wpce_driver); |
| } |
| |
| struct i2c_client *wpce_get_i2c_client(void) |
| { |
| return g_i2cec_client; |
| } |
| EXPORT_SYMBOL_GPL(wpce_get_i2c_client); |
| |
| void wpce_poweroff(void) |
| { |
| if (g_i2cec_client == NULL) |
| return; |
| i2c_smbus_write_byte(g_i2cec_client, EC_CMD_POWER_OFF); |
| } |
| EXPORT_SYMBOL_GPL(wpce_poweroff); |
| |
| void wpce_restart(void) |
| { |
| if (g_i2cec_client == NULL) |
| return; |
| i2c_smbus_write_byte(g_i2cec_client, EC_CMD_RESTART); |
| } |
| EXPORT_SYMBOL_GPL(wpce_restart); |
| |
| int wpce_i2c_transfer(struct i2c_msg *msg) |
| { |
| if (g_i2cec_client == NULL) |
| return -1; |
| msg->addr = g_i2cec_client->addr; |
| return i2c_transfer(g_i2cec_client->adapter, msg, 1); |
| } |
| EXPORT_SYMBOL_GPL(wpce_i2c_transfer); |
| |
| int wpce_smbus_write_word_data(u8 command, u16 value) |
| { |
| if (g_i2cec_client == NULL) |
| return -1; |
| return i2c_smbus_write_word_data(g_i2cec_client, command, value); |
| } |
| EXPORT_SYMBOL_GPL(wpce_smbus_write_word_data); |
| |
| int wpce_smbus_write_byte_data(u8 command, u8 value) |
| { |
| if (g_i2cec_client == NULL) |
| return -1; |
| return i2c_smbus_write_byte_data(g_i2cec_client, command, value); |
| } |
| EXPORT_SYMBOL_GPL(wpce_smbus_write_byte_data); |
| |
| module_init(wpce_init); |
| module_exit(wpce_exit); |
| |
| MODULE_AUTHOR("Quanta Computer Inc."); |
| MODULE_DESCRIPTION("Quanta Embedded Controller I2C Bridge Driver"); |
| MODULE_LICENSE("GPL v2"); |