meta-facebook/meta-galaxy100/recipes-kernel/i2c-mode/files/galaxy100_ec.c (629 lines of code) (raw):
/*
* galaxy100_ec.c - The i2c driver for EC
*
* Copyright 2015-present Facebook. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//#define DEBUG
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <i2c_dev_sysfs.h>
#ifdef DEBUG
#define EC_DEBUG(fmt, ...) do { \
printk(KERN_DEBUG "%s:%d " fmt "\n", \
__FUNCTION__, __LINE__, ##__VA_ARGS__); \
} while (0)
#else /* !DEBUG */
#define EC_DEBUG(fmt, ...)
#endif
#define EC_MAC_LEN 6
#define EC_SERIAL_NUM 32
#define EC_PRODUCT_NAME_LEN 4
#define EC_CUST_NAME_LEN 3
#define EC_DELAY 11 //ms
static int i2c_smbus_read_byte_data_retry(struct i2c_client *client, unsigned char reg)
{
int count = 10;
int ret = -1;
while((ret < 0 || ret == 0xff) && count--) {
ret = i2c_smbus_read_byte_data(client, reg);
}
return ret;
}
static ssize_t ec_cpu_temp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "%d\n", val * 10);
}
static ssize_t ec_mem_temp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int lsb_val, msb_val;
int result;
mutex_lock(&data->idd_lock);
msb_val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
lsb_val = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
mutex_unlock(&data->idd_lock);
if (lsb_val < 0 || msb_val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
result = ((((msb_val << 8) + lsb_val) >> 4) & 0xff) * 10 + (((lsb_val >> 1) & 0x07) * 10)/ 8;
//return scnprintf(buf, PAGE_SIZE, "%d.%d C\n", result / 8, (((result % 8) * 10) / 8));
return scnprintf(buf, PAGE_SIZE, "%d\n", result);
}
static ssize_t ec_wdt_cfg_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);
}
static ssize_t ec_wdt_crm_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t ec_wdt_crs_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t ec_hw_monitor_cfg_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);
}
static ssize_t ec_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val_r, val_e, val_t;
int year, month, day;
mutex_lock(&data->idd_lock);
val_r = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
val_e = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
msleep(EC_DELAY);
val_t = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x2));
mutex_unlock(&data->idd_lock);
if (val_r < 0 || val_e < 0 || val_t < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
if(val_t >> 7) {
mutex_lock(&data->idd_lock);
year = i2c_smbus_read_byte_data_retry(client, 0x2d);
year &= 0x0f;
msleep(EC_DELAY);
month = i2c_smbus_read_byte_data_retry(client, 0x2e);
msleep(EC_DELAY);
day = i2c_smbus_read_byte_data_retry(client, 0x2f);
mutex_unlock(&data->idd_lock);
return scnprintf(buf, PAGE_SIZE, "%d%02x%02xT%02x\n", year, month, day, val_t & 0x0f);
} else {
return scnprintf(buf, PAGE_SIZE, "V%02dE%02d\n", val_r, val_e);
}
}
static ssize_t ec_gpio_dir_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);
}
static ssize_t ec_gpio_data_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int val;
mutex_lock(&data->idd_lock);
val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
mutex_unlock(&data->idd_lock);
if (val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);
}
static ssize_t ec_build_date_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int year, month, day;
mutex_lock(&data->idd_lock);
year = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
if (year < 0) {
/* error case */
EC_DEBUG("I2C read 0x%x error!\n", dev_attr->ida_reg);
return -1;
}
msleep(EC_DELAY);
month = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg + 1);
if (month < 0) {
/* error case */
EC_DEBUG("I2C read 0x%x error!\n", dev_attr->ida_reg + 1);
return -1;
}
msleep(EC_DELAY);
day = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg + 2);
if (day < 0) {
/* error case */
EC_DEBUG("I2C read 0x%x error!\n", dev_attr->ida_reg + 2);
return -1;
}
mutex_unlock(&data->idd_lock);
return scnprintf(buf, PAGE_SIZE, "20%x-%x-%x\n", year, month, day);
}
static ssize_t ec_cpu_vol_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int lsb_val, msb_val;
int result;
mutex_lock(&data->idd_lock);
lsb_val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
msb_val = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
mutex_unlock(&data->idd_lock);
if (lsb_val < 0 || msb_val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
result = (msb_val << 8) + lsb_val;
//scnprintf(buf, PAGE_SIZE, "%d.%d V\n", result / 341, (((result % 341) * 10) / 341));
return scnprintf(buf, PAGE_SIZE, "%d\n", result);
}
static ssize_t ec_3v_vol_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int lsb_val, msb_val;
int result;
mutex_lock(&data->idd_lock);
lsb_val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
msb_val = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
mutex_unlock(&data->idd_lock);
if (lsb_val < 0 || msb_val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
result = ((msb_val << 8) + lsb_val) * 2;
//scnprintf(buf, PAGE_SIZE, "%d.%d V\n", result / 341, (((result % 341) * 10) / 341));
return scnprintf(buf, PAGE_SIZE, "%d\n", result);
}
static ssize_t ec_5v_vol_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int lsb_val, msb_val;
int result;
mutex_lock(&data->idd_lock);
lsb_val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
msb_val = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
mutex_unlock(&data->idd_lock);
if (lsb_val < 0 || msb_val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
result = ((msb_val << 8) + lsb_val) * 16;
//scnprintf(buf, PAGE_SIZE, "%d.%d V\n", result / 1705, (((result % 1705) * 10) / 1705));
return scnprintf(buf, PAGE_SIZE, "%d\n", result);
}
static ssize_t ec_12v_vol_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int lsb_val, msb_val;
int result;
mutex_lock(&data->idd_lock);
lsb_val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
msb_val = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
mutex_unlock(&data->idd_lock);
if (lsb_val < 0 || msb_val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
result = ((msb_val << 8) + lsb_val) * 33;
//scnprintf(buf, PAGE_SIZE, "%d.%d V\n", result / 1705, (((result % 1705) * 10) / 1705));
return scnprintf(buf, PAGE_SIZE, "%d\n", result);
}
static ssize_t ec_dimm_vol_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int lsb_val, msb_val;
int result;
mutex_lock(&data->idd_lock);
lsb_val = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg);
msleep(EC_DELAY);
msb_val = i2c_smbus_read_byte_data_retry(client, (dev_attr->ida_reg + 0x1));
mutex_unlock(&data->idd_lock);
if (lsb_val < 0 || msb_val < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
result = (msb_val << 8) + lsb_val;
//scnprintf(buf, PAGE_SIZE, "%d.%d V\n", result / 341, (((result % 341) * 10) / 341));
return scnprintf(buf, PAGE_SIZE, "%d\n", result);
}
static ssize_t ec_product_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int result, i, len = EC_PRODUCT_NAME_LEN;
unsigned char product_name[EC_PRODUCT_NAME_LEN];
mutex_lock(&data->idd_lock);
for(i = 0; i < len; i++) {
result = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg + i);
if (result < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
product_name[i] = (unsigned char)result;
msleep(EC_DELAY);
}
mutex_unlock(&data->idd_lock);
return scnprintf(buf, PAGE_SIZE, "%c%c%c%c\n",
product_name[0], product_name[1], product_name[2], product_name[3]);
}
static ssize_t ec_customize_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int result, i, len = EC_CUST_NAME_LEN;
unsigned char cust_name[EC_CUST_NAME_LEN];
mutex_lock(&data->idd_lock);
for(i = 0; i < len; i++) {
result = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg + i);
if (result < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
cust_name[i] = (unsigned char)result;
msleep(EC_DELAY);
}
mutex_unlock(&data->idd_lock);
return scnprintf(buf, PAGE_SIZE, "%s\n", cust_name);
}
static ssize_t ec_mac_addr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int result, i, len = EC_MAC_LEN;
unsigned char mac[EC_MAC_LEN];
mutex_lock(&data->idd_lock);
for(i = 0; i < len; i++) {
result = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg + i);
if (result < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
mac[i] = (unsigned char)result;
msleep(EC_DELAY);
}
mutex_unlock(&data->idd_lock);
return scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
static ssize_t ec_serial_number_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_dev_data_st *data = i2c_get_clientdata(client);
i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);
const i2c_dev_attr_st *dev_attr = i2c_attr->isa_i2c_attr;
int result, i, len = EC_SERIAL_NUM;
unsigned char serial[EC_SERIAL_NUM];
mutex_lock(&data->idd_lock);
for(i = 0; i < len; i++) {
result = i2c_smbus_read_byte_data_retry(client, dev_attr->ida_reg + i);
if (result < 0) {
/* error case */
EC_DEBUG("I2C read error!\n");
return -1;
}
serial[i] = (unsigned char)result;
//msleep(EC_DELAY / 4);
}
mutex_unlock(&data->idd_lock);
return scnprintf(buf, PAGE_SIZE, "%s\n", serial);
}
static const i2c_dev_attr_st ec_attr_table[] = {
{
"temp1_input",
NULL,
ec_cpu_temp_show,
NULL,
0, 0, 8,
},
{
"temp2_input",
NULL,
ec_mem_temp_show,
NULL,
0x4, 0, 8,
},
{
"wdt_cfg",
NULL,
ec_wdt_cfg_show,
NULL,
0x6, 0, 8,
},
{
"wdt_crm",
NULL,
ec_wdt_crm_show,
NULL,
0x7, 0, 8,
},
{
"wdt_crs",
NULL,
ec_wdt_crs_show,
NULL,
0x8, 0, 8,
},
{
"hw_monitor_cfg",
NULL,
ec_hw_monitor_cfg_show,
NULL,
0x15, 0, 8,
},
{
"version",
NULL,
ec_version_show,
NULL,
0x1d, 0, 8,
},
{
"in0_input",
NULL,
ec_cpu_vol_show,
NULL,
0x20, 0, 8,
},
{
"in1_input",
NULL,
ec_3v_vol_show,
NULL,
0x22, 0, 8,
},
{
"in2_input",
NULL,
ec_5v_vol_show,
NULL,
0x24, 0, 8,
},
{
"gpio_dir",
NULL,
ec_gpio_dir_show,
NULL,
0x2b, 0, 8,
},
{
"gpio_data",
NULL,
ec_gpio_data_show,
NULL,
0x2c, 0, 8,
},
{
"build_date_input",
NULL,
ec_build_date_show,
NULL,
0x2d, 0, 8,
},
{
"in3_input",
NULL,
ec_12v_vol_show,
NULL,
0x30, 0, 8,
},
{
"in4_input",
NULL,
ec_dimm_vol_show,
NULL,
0x32, 0, 8,
},
{
"product_name",
NULL,
ec_product_name_show,
NULL,
0x3c, 0, 8,
},
{
"customize_name_input",
NULL,
ec_customize_name_show,
NULL,
0x4d, 0, 8,
},
{
"mac_addr",
NULL,
ec_mac_addr_show,
NULL,
0x50, 0, 8,
},
{
"serial_number",
NULL,
ec_serial_number_show,
NULL,
0x60, 0, 8,
},
};
static i2c_dev_data_st ec_data;
/*
* EC i2c addresses.
*/
static const unsigned short normal_i2c[] = {
0x33, I2C_CLIENT_END
};
/* EC id */
static const struct i2c_device_id ec_id[] = {
{"galaxy100_ec", 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, ec_id);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int ec_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
/*
* We don't currently do any detection of the EC
*/
strlcpy(info->type, "galaxy100_ec", I2C_NAME_SIZE);
return 0;
}
static int ec_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int n_attrs = sizeof(ec_attr_table) / sizeof(ec_attr_table[0]);
return i2c_dev_sysfs_data_init(client, &ec_data,
ec_attr_table, n_attrs);
}
static int ec_remove(struct i2c_client *client)
{
i2c_dev_sysfs_data_clean(client, &ec_data);
return 0;
}
static struct i2c_driver ec_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "galaxy100_ec",
},
.probe = ec_probe,
.remove = ec_remove,
.id_table = ec_id,
.detect = ec_detect,
.address_list = normal_i2c,
};
static int __init ec_mod_init(void)
{
return i2c_add_driver(&ec_driver);
}
static void __exit ec_mod_exit(void)
{
i2c_del_driver(&ec_driver);
}
MODULE_AUTHOR("Mickey Zhan");
MODULE_DESCRIPTION("EC Driver");
MODULE_LICENSE("GPL");
module_init(ec_mod_init);
module_exit(ec_mod_exit);