/*
 * 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.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/swab.h>

#define USE_SMBUS    1

#define FAN_NUM  5 
#define PSU_NUM  2 

static struct device *psoc_led_client_dev = NULL;

struct __attribute__ ((__packed__))  psoc_psu_layout {
    u16 psu1_iin;
    u16 psu2_iin;
    u16 psu1_iout;
    u16 psu2_iout;
    
    u16 psu1_pin;
    u16 psu2_pin;
    u16 psu1_pout;
    u16 psu2_pout;
    
    u16 psu1_vin;
    u16 psu2_vin;
    u16 psu1_vout;
    u16 psu2_vout;
};

struct __attribute__ ((__packed__))  psoc_layout {
    u8 ctl;                 //offset: 0
    u16 switch_temp;        //offset: 1
    u8 reserve1;            //offset: 3

    u8 fw_upgrade;          //offset: 4

    //i2c bridge
    u8 i2c_st;              //offset: 5
    u8 i2c_ctl;             //offset: 6
    u8 i2c_addr;            //offset: 7
    u8 i2c_data[0x20];      //offset: 8

    //gpo
    u8 led_grn;             //offset: 28
    u8 led_red;             //offset: 29

    //pwm duty
    u8 pwm[FAN_NUM];        //offset: 2a
    u8 pwm_psu[PSU_NUM];    //offset: 2f

    //fan rpm
    u16 fan[FAN_NUM*2];     //offset: 31
    //u16 fan_psu[PSU_NUM];

    //gpi 
    u8 gpi_fan;             //offset: 45

    //psu state
    u8 psu_state;           //offset: 46

    //temperature
    u16 temp[5];            //offset: 47
    u16 temp_psu[PSU_NUM];  //offset: 51

    //version
    u8 version[2];          //offset: 55
    
    u8  reserve2[3];        //offset: 57
    struct psoc_psu_layout psu_info;      //offset: 5a
};        


/* definition */
#define PSOC_OFF(m)    offsetof(struct psoc_layout, m)
#define PSOC_PSU_OFF(m)    offsetof(struct psoc_psu_layout, m)

#define SWITCH_TMP_OFFSET       PSOC_OFF(switch_temp) //0x01
#define PWM_OFFSET              PSOC_OFF(pwm)
#define PWM_PSU_OFFSET          PSOC_OFF(pwm_psu)
#define THERMAL_OFFSET          PSOC_OFF(temp)
#define RPM_OFFSET              PSOC_OFF(fan)
#define DIAG_FLAG_OFFSET        PSOC_OFF(ctl)
#define FAN_LED_OFFSET          PSOC_OFF(led_grn)
#define FAN_GPI_OFFSET          PSOC_OFF(gpi_fan)
#define PSOC_PSU_OFFSET         PSOC_OFF(psu_state)
#define VERSION_OFFSET          PSOC_OFF(version)
#define PSU_INFO_OFFSET         PSOC_OFF(psu_info)


/* Each client has this additional data */
struct psoc_data {
	struct device		*hwmon_dev;
	struct mutex		update_lock;
	u32                 diag;
};

/*-----------------------------------------------------------------------*/

static ssize_t psoc_i2c_read(struct i2c_client *client, u8 *buf, u8 offset, size_t count)
{
#if USE_SMBUS    
	int i;
	
    for(i=0; i<count; i++) {
        buf[i] = i2c_smbus_read_byte_data(client, offset+i);
    }	
    return count;
#else
	struct i2c_msg msg[2];
	char msgbuf[2];
	int status;

	memset(msg, 0, sizeof(msg));
	
	msgbuf[0] = offset;
	
	msg[0].addr = client->addr;
	msg[0].buf = msgbuf;
	msg[0].len = 1;

	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].buf = buf;
	msg[1].len = count;
	
	status = i2c_transfer(client->adapter, msg, 2);
	
	if(status == 2)
	    status = count;
	    
	return status;    
#endif	
}

static ssize_t psoc_i2c_write(struct i2c_client *client, char *buf, unsigned offset, size_t count)
{
#if USE_SMBUS    
	int i;
	
    for(i=0; i<count; i++) {
        i2c_smbus_write_byte_data(client, offset+i, buf[i]);
    }	
    return count;
#else
	struct i2c_msg msg;
	int status;
    u8 writebuf[256];
	
	int i = 0;

	msg.addr = client->addr;
	msg.flags = 0;

	/* msg.buf is u8 and casts will mask the values */
	msg.buf = writebuf;
	
	msg.buf[i++] = offset;
	memcpy(&msg.buf[i], buf, count);
	msg.len = i + count;
	
	status = i2c_transfer(client->adapter, &msg, 1);
	if (status == 1)
		status = count;
	
    return status;	
#endif    
}

static u16 psoc_read16(struct i2c_client *client, u8 offset)
{
	u16 value = 0;
	u8 buf[2];
    
    if(psoc_i2c_read(client, buf, offset, 2) == 2)
        value = (buf[0]<<8 | buf[1]<<0);
    
	return value;
}

static u8 psoc_read8(struct i2c_client *client, u8 offset)
{
	u8 value = 0;
	u8 buf = 0;
    
    if(psoc_i2c_read(client, &buf, offset, 1) == 1)
        value = buf;
    
	return value;
}

//PSOC i2c bridge regsters
#define PSOC_I2C_STATUS         PSOC_OFF(i2c_st)
#define PSOC_I2C_CNTRL          PSOC_OFF(i2c_ctl)
#define PSOC_I2C_ADDR           PSOC_OFF(i2c_addr)
#define PSOC_I2C_DATA           PSOC_OFF(i2c_data)

//status bit definition
#define PSOC_I2C_START          (1 << 0)
#define PSOC_PMB_SEL            (1 << 7)

//addr bits definition
#define PSOC_I2C_READ           (1 << 0)

//PMBUS registers definition
#define PMBUS_READ_VIN                  (0x88)
#define PMBUS_READ_IIN                  (0x89)
#define PMBUS_READ_VOUT                 (0x8B)
#define PMBUS_READ_IOUT                 (0x8C)
#define PMBUS_READ_POUT                 (0x96)
#define PMBUS_READ_PIN                  (0x97)

#define PMBUS_MFR_ID                    (0x99)
#define PMBUS_MFR_MODEL                 (0x9A)
#define PMBUS_MFR_REVISION              (0x9B)
#define PMBUS_MFR_DATE                  (0x9D)
#define PMBUS_MFR_SERIAL                (0x9E)

static unsigned char psu1_data_model[32], psu2_data_model[32];
static unsigned char psu1_data_sn[32], psu2_data_sn[32];
static struct mutex  psu_data_lock;

static int psoc_i2c_bridge_read(struct i2c_client *client,
                                unsigned char bus, 
                                unsigned char chip, 
                                unsigned char *addr,
				int alen, 
                                unsigned char *data,
				int len )
{
    unsigned char txdata[28], rxdata[28];
    int index, timeout;
    unsigned char *inv_data;

	txdata[PSOC_I2C_STATUS] = 0;		/* the status */
	txdata[PSOC_I2C_CNTRL] = ((alen & 3) << 5) | (len & 0x1f);	/* the sizes */
	txdata[PSOC_I2C_ADDR] = (chip << 1) | PSOC_I2C_READ;		/* read address */
	for(index = 0; index < alen; index++)
		txdata[PSOC_I2C_DATA + index] = addr[index];		/* the chip address */
	for(; index < alen+len; index++)
		txdata[PSOC_I2C_DATA + index] = 0;		/* clear the chip data */
		
    psoc_i2c_write(client, &txdata[PSOC_I2C_CNTRL], PSOC_I2C_CNTRL, 2 + alen + len);
    
    //delay a while ???
    //---------------------------------------------------------------------
    //start write
    txdata[PSOC_I2C_STATUS] = PSOC_I2C_START;       /* the start bit*/
    if(bus)
        txdata[PSOC_I2C_STATUS] |= PSOC_PMB_SEL;/* bus id */
    psoc_i2c_write(client, &txdata[PSOC_I2C_STATUS], PSOC_I2C_STATUS, 1);
    
    //delay a while
    timeout = 40; //40*20==>800 ms
    do {
        psoc_i2c_read(client, &rxdata[PSOC_I2C_STATUS], PSOC_I2C_STATUS, 1);
        
        //check rxdata[5] error bit(1) and complete bit(0) ,TBD
		if((rxdata[PSOC_I2C_STATUS] & 0x2) == 0x2) {
		    //printk("i2c bridge fail!!!\n");
			timeout = 0;
			break;
		}
		if((rxdata[PSOC_I2C_STATUS] & PSOC_I2C_START) == 0) {
		    /* comand complete */
            psoc_i2c_read(client, &rxdata[PSOC_I2C_DATA+alen], PSOC_I2C_DATA+alen, len);
			break;	
		}
		
        //delay
        msleep(20);
    } while(timeout--);

 	if(timeout <= 0) {
 	    return -1;
 	}
    
    //---------------------------------------------------------------------
    for(index=0; index < len; index++) {
        data[index] = rxdata[PSOC_I2C_DATA + alen + index];
    }

    if (*addr == PMBUS_MFR_MODEL) {
	if (chip == 0x58) {
	    inv_data = &psu1_data_model[0];
	}
	else
	if (chip == 0x59) {
	    inv_data = &psu2_data_model[0];
	}
	else {
	    inv_data = NULL;
	}
    }
    else
    if (*addr == PMBUS_MFR_SERIAL) {
	if (chip == 0x58) {
	    inv_data = &psu1_data_sn[0];
	}
	else
	if (chip == 0x59) {
	    inv_data = &psu2_data_sn[0];
	}
	else {
	    inv_data = NULL;
	}
    }
    else {
	inv_data = NULL;
    }

    if (inv_data) {
	mutex_lock(&psu_data_lock);
	memset(inv_data, 0, 32);
	for(index=0; index < len; index++) {
	    inv_data[index] = data[index];
	}
	inv_data[index] = '\0';
	mutex_unlock(&psu_data_lock);
    }

    return 0;
}


/*
CPLD report the PSU0 status
000 = PSU normal operation
100 = PSU fault
010 = PSU unpowered
111 = PSU not installed

7 6 | 5 4 3 |  2 1 0
----------------------
    | psu1  |  psu0
*/
static char* psu_str[] = {
    "normal",           //000
    "NA",               //001
    "unpowered",        //010
    "NA",               //011
    "fault",            //100
    "NA",               //101
    "NA",               //110
    "not installed",    //111
};

static ssize_t show_psu_st(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u32 status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 byte;
	int shift = (attr->index == 0)?3:0;
    
	mutex_lock(&data->update_lock);
    status = psoc_i2c_read(client, &byte, PSOC_PSU_OFFSET, 1);
	mutex_unlock(&data->update_lock);
	
    byte = (byte >> shift) & 0x7;
	
	status = sprintf (buf, "%d : %s\n", byte, psu_str[byte]);
	    
	return strlen(buf);
}

static ssize_t psoc_show_psu_st(char *buf, int psu_index)
{
	u32 status;
	struct i2c_client *client = NULL;
	struct psoc_data *data = NULL;
	u8 byte;
	int shift = (psu_index == 0)?3:0;

	if (!psoc_led_client_dev) {
	    return 0;
	}

	client = to_i2c_client(psoc_led_client_dev);
	data = i2c_get_clientdata(client);

	mutex_lock(&data->update_lock);
    status = psoc_i2c_read(client, &byte, PSOC_PSU_OFFSET, 1);
	mutex_unlock(&data->update_lock);

    byte = (byte >> shift) & 0x7;

	status = sprintf (buf, "%d : %s\n", byte, psu_str[byte]);

	return strlen(buf);
}

ssize_t psoc_show_psu_state(char *buf, int index)
{
	return psoc_show_psu_st(buf, index);
}
EXPORT_SYMBOL(psoc_show_psu_state);

/*-----------------------------------------------------------------------*/

/* sysfs attributes for hwmon */

static ssize_t show_thermal(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u16 status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 offset = attr->index * 2 + THERMAL_OFFSET;
    
	mutex_lock(&data->update_lock);
	
	status = psoc_read16(client, offset);
	status = __swab16(status);
	
	mutex_unlock(&data->update_lock);
	
	return sprintf(buf, "%d\n",
		       (s8)(status>>8) * 1000  );
}


static ssize_t show_pwm(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	int status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 offset = attr->index;
    
	mutex_lock(&data->update_lock);
	
	status = psoc_read8(client, offset);
	
	mutex_unlock(&data->update_lock);
	
	return sprintf(buf, "%d\n",
		       status);
}

static ssize_t set_pwm(struct device *dev,
			   struct device_attribute *devattr,
			   const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 offset = attr->index;

	u8 pwm = simple_strtol(buf, NULL, 10);
	if(pwm > 255) pwm = 255;
	
	if(data->diag) {    
    	mutex_lock(&data->update_lock);
    	psoc_i2c_write(client, &pwm, offset, 1);
    	mutex_unlock(&data->update_lock);
    }
	
	return count;
}


static ssize_t show_rpm(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	int status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 offset = attr->index;
    
	mutex_lock(&data->update_lock);
	
	status = psoc_read16(client, offset);
	status = __swab16(status);
	
	mutex_unlock(&data->update_lock);
	
	return sprintf(buf, "%d\n",
		       status);
}
static ssize_t show_fan_type(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u8 status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 index = attr->index;
	int type = -1;
    
	mutex_lock(&data->update_lock);
	status = psoc_read8(client, FAN_GPI_OFFSET);
	mutex_unlock(&data->update_lock);

	if( (status & 1<<index) == 0) {
	    if( (status & 1<<(index+4) ) == 0) {
	        type = 1;//NORMAL FAN
	    }
	    else {
	        type = 2;//REVERSAL FAN
	    }
	}
	else {
	    type = 0;//UNPLUGGED
	}
	
	return sprintf(buf, "%d\n", type);
}

static ssize_t psoc_show_rpm(char *buf, int fan_index)
{
	int status;
	struct i2c_client *client = NULL;
	struct psoc_data *data = NULL;
	u8 offset = fan_index*2  + RPM_OFFSET;

	if (!psoc_led_client_dev) {
	    return 0;
	}

	client = to_i2c_client(psoc_led_client_dev);
	data = i2c_get_clientdata(client);

	mutex_lock(&data->update_lock);
	status = psoc_read16(client, offset);
	mutex_unlock(&data->update_lock);

	return sprintf(buf, "%d\n",
		       status);
}

ssize_t psoc_show_fan_input(char *buf, int index)
{
	return psoc_show_rpm(buf, index);
}
EXPORT_SYMBOL(psoc_show_fan_input);

static ssize_t show_switch_tmp(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u16 status;
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u16 temp = 0;
    
	mutex_lock(&data->update_lock);
    status = psoc_i2c_read(client, (u8*)&temp, SWITCH_TMP_OFFSET, 2);
	status = __swab16(status);
	mutex_unlock(&data->update_lock);
	
	status = sprintf (buf, "%d\n",  (s8)(temp>>8) * 1000  );
	    
	return strlen(buf);
}

static ssize_t set_switch_tmp(struct device *dev,
			   struct device_attribute *devattr,
			   const char *buf, size_t count)
{
	//struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);

	long temp = simple_strtol(buf, NULL, 10);
    u16 temp2 =  ( (temp/1000) <<8 ) & 0xFF00 ;
    
	mutex_lock(&data->update_lock);
	psoc_i2c_write(client, (u8*)&temp2, SWITCH_TMP_OFFSET, 2);
	mutex_unlock(&data->update_lock);
	
	return count;
}

static ssize_t show_diag(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u16 status;
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 diag_flag = 0;
    
	mutex_lock(&data->update_lock);
    status = psoc_i2c_read(client, (u8*)&diag_flag, DIAG_FLAG_OFFSET, 1);
	mutex_unlock(&data->update_lock);
	
	data->diag = (diag_flag & 0x80)?1:0;
	status = sprintf (buf, "%d\n", data->diag);
	    
	return strlen(buf);
}

static ssize_t set_diag(struct device *dev,
			   struct device_attribute *devattr,
			   const char *buf, size_t count)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 value = 0;
	u8 diag = simple_strtol(buf, NULL, 10);
	
	diag = diag?1:0;
	data->diag = diag;
	    
	mutex_lock(&data->update_lock);
	psoc_i2c_read(client, (u8*)&value, DIAG_FLAG_OFFSET, 1);
	if(diag) value |= (1<<7);
	else     value &= ~(1<<7);
	psoc_i2c_write(client, (u8*)&value, DIAG_FLAG_OFFSET, 1);
	mutex_unlock(&data->update_lock);
	
	return count;
}

static ssize_t show_version(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u16 status;
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
    
	mutex_lock(&data->update_lock);
	
	status = psoc_read16(client, VERSION_OFFSET);
	
	mutex_unlock(&data->update_lock);
	
	return sprintf(buf, "ver: %x.%x\n", (status & 0xFF00)>>8,  (status & 0xFF) );
}


static ssize_t show_fan_led(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	int status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 bit = attr->index;
    
	mutex_lock(&data->update_lock);
	
	status = psoc_read8(client, FAN_LED_OFFSET);
	
	mutex_unlock(&data->update_lock);
	
	return sprintf(buf, "%d\n",
		       (status & (1<<bit))?1:0 );
}

static ssize_t set_fan_led(struct device *dev,
			   struct device_attribute *devattr,
			   const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 bit = attr->index;
	u8 led_state = 0;

	u8 v = simple_strtol(buf, NULL, 10);
	
	if(data->diag) {    
    	mutex_lock(&data->update_lock);
    	led_state = psoc_read8(client, FAN_LED_OFFSET);
    	if(v) led_state |=  (1<<bit);
    	else  led_state &= ~(1<<bit);    
    	psoc_i2c_write(client, &led_state, FAN_LED_OFFSET, 1);
    	mutex_unlock(&data->update_lock);
    }
	
	return count;
}

static ssize_t show_value8(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	int status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 offset = attr->index;

	mutex_lock(&data->update_lock);

	status = psoc_read8(client, offset);

	mutex_unlock(&data->update_lock);

	return sprintf(buf, "0x%02X\n", status );
}

ssize_t psoc_show_value8(char *buf, int offset)
{
	int status;
	struct i2c_client *client = NULL;
	struct psoc_data *data = NULL;

	if (!psoc_led_client_dev) {
	    return 0;
	}

	client = to_i2c_client(psoc_led_client_dev);
	data = i2c_get_clientdata(client);

	mutex_lock(&data->update_lock);
	status = psoc_read8(client, offset);
	mutex_unlock(&data->update_lock);

	return sprintf(buf, "0x%02X\n", status );
}

static char prev_fan_state[8] = { 0 };

ssize_t psoc_show_fan_state(char *buf)
{
    int i;
    int rv = psoc_show_value8(buf, FAN_GPI_OFFSET);
    for (i = 0; i < 3; i++) {
	if (strncmp(prev_fan_state, buf, 4) == 0) {
	    return rv;
	}
	msleep(500);
	rv = psoc_show_value8(buf, FAN_GPI_OFFSET);
    }
    strcpy(prev_fan_state, buf);
    return rv;
}
EXPORT_SYMBOL(psoc_show_fan_state);

static long pmbus_reg2data_linear(int data, int linear16)
{
    s16 exponent;
    s32 mantissa;
    long val;

    if (linear16) { /* LINEAR16 */
        exponent = -9;
        mantissa = (u16) data;
    } else {  /* LINEAR11 */
        exponent = ((s16)data) >> 11;
        exponent = ((s16)( data & 0xF800) ) >> 11;
        mantissa = ((s32)((data & 0x7ff) << 5)) >> 5;
    }

    //printk("data=%d,  m=%d, e=%d\n", data, exponent, mantissa);
    val = mantissa;

    /* scale result to micro-units for power sensors */
    val = val * 1000L;

    if (exponent >= 0)
        val <<= exponent;
    else
        val >>= -exponent;

    return val;
}

static ssize_t show_psu(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	int status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 reg  = attr->index & 0xFF;
    u8 len  = ((attr->index & 0xFF00) >> 8);
	u8 chip = (attr->index >> 16)? 0x59:0x58;
	u8 bus  = 1;
	unsigned char value[2] = {0,0};;    

	if (len == 2)
	{
		mutex_lock(&data->update_lock);
		psoc_i2c_bridge_read(client, bus, chip, &reg, 1, value, 2);
		mutex_unlock(&data->update_lock);

		status =  value[1]<<8 | value[0];

		return sprintf(buf, "%ld\n", pmbus_reg2data_linear(status, (reg==PMBUS_READ_VOUT)?1:0) );
	}
	else
	{	//len is not defined.
        u8 tmpbuf[32];
		mutex_lock(&data->update_lock);
        //length of block read
		psoc_i2c_bridge_read(client, bus, chip, &reg, 1, &len, 1);
        //data included length
		psoc_i2c_bridge_read(client, bus, chip, &reg, 1, tmpbuf, len+1); 
		mutex_unlock(&data->update_lock);

		memcpy(buf, tmpbuf+1, len);	
		buf[len]='\n';

		return len+1;
	}
}


static ssize_t show_psu1_model(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	ssize_t ret;

	mutex_lock(&psu_data_lock);
	ret = sprintf(buf, "%s\n", psu1_data_model);
	mutex_unlock(&psu_data_lock);
	return ret;
}

static ssize_t show_psu1_sn(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	ssize_t ret;

	mutex_lock(&psu_data_lock);
	ret = sprintf(buf, "%s\n", psu1_data_sn);
	mutex_unlock(&psu_data_lock);
	return ret;
}

static ssize_t show_psu2_model(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	ssize_t ret;

	mutex_lock(&psu_data_lock);
	ret = sprintf(buf, "%s\n", psu2_data_model);
	mutex_unlock(&psu_data_lock);
	return ret;
}

static ssize_t show_psu2_sn(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	ssize_t ret;

	mutex_lock(&psu_data_lock);
	ret = sprintf(buf, "%s\n", psu2_data_sn);
	mutex_unlock(&psu_data_lock);
	return ret;
}

static ssize_t show_psu_psoc(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	u16 status;
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct psoc_data *data = i2c_get_clientdata(client);
	u8 offset = attr->index + PSU_INFO_OFFSET;

	mutex_lock(&data->update_lock);
	status = psoc_read16(client, offset);
	mutex_unlock(&data->update_lock);

	return sprintf(buf, "%ld \n", pmbus_reg2data_linear(status, strstr(attr->dev_attr.attr.name, "vout")? 1:0 ));
}

static ssize_t psoc_show_psu_psoc(char *buf, int psu_index, char *attr_name)
{
	u16 status;
	struct i2c_client *client = NULL;
	struct psoc_data *data = NULL;
	u8 offset = psu_index + PSU_INFO_OFFSET;

	if (!psoc_led_client_dev) {
	    return 0;
	}

	client = to_i2c_client(psoc_led_client_dev);
	data = i2c_get_clientdata(client);

	mutex_lock(&data->update_lock);
	status = psoc_read16(client, offset);
	mutex_unlock(&data->update_lock);

	return sprintf(buf, "%ld \n", pmbus_reg2data_linear(status, strstr(attr_name, "vout")? 1:0 ));
}

ssize_t psoc_show_psu_vin(char *buf, int index)
{
	return psoc_show_psu_psoc(buf, index, "vin");
}
EXPORT_SYMBOL(psoc_show_psu_vin);

ssize_t psoc_show_diag(char *buf)
{
	u16 status;
	struct i2c_client *client = NULL;
	struct psoc_data *data = NULL;
	u8 diag_flag = 0;

	if (!psoc_led_client_dev) {
	    return 0;
	}

	client = to_i2c_client(psoc_led_client_dev);
	data = i2c_get_clientdata(client);

	mutex_lock(&data->update_lock);
    status = psoc_i2c_read(client, (u8*)&diag_flag, DIAG_FLAG_OFFSET, 1);
	mutex_unlock(&data->update_lock);

	data->diag = (diag_flag & 0x80)?1:0;
	status = sprintf (buf, "%d\n", data->diag);

	return strlen(buf);
}
EXPORT_SYMBOL(psoc_show_diag);

ssize_t psoc_set_diag(const char *buf, size_t count)
{
	struct i2c_client *client = NULL;
	struct psoc_data *data = NULL;
	u8 value = 0;
	u8 diag = simple_strtol(buf, NULL, 10);

	if (!psoc_led_client_dev) {
	    return 0;
	}

	client = to_i2c_client(psoc_led_client_dev);
	data = i2c_get_clientdata(client);

    diag = diag?1:0;
	data->diag = diag;

	mutex_lock(&data->update_lock);
	psoc_i2c_read(client, (u8*)&value, DIAG_FLAG_OFFSET, 1);
	if(diag) value |= (1<<7);
	else     value &= ~(1<<7);
	psoc_i2c_write(client, (u8*)&value, DIAG_FLAG_OFFSET, 1);
	mutex_unlock(&data->update_lock);

	return count;
}
EXPORT_SYMBOL(psoc_set_diag);


static SENSOR_DEVICE_ATTR(temp1_input,	S_IRUGO,	show_thermal, 0, 0);
static SENSOR_DEVICE_ATTR(temp2_input,	S_IRUGO,	show_thermal, 0, 1);
static SENSOR_DEVICE_ATTR(temp3_input,	S_IRUGO,	show_thermal, 0, 2);
static SENSOR_DEVICE_ATTR(temp4_input,	S_IRUGO,	show_thermal, 0, 3);
static SENSOR_DEVICE_ATTR(temp5_input,	S_IRUGO,	show_thermal, 0, 4);
static SENSOR_DEVICE_ATTR(thermal_psu1,	S_IRUGO,	show_thermal, 0, 5);
static SENSOR_DEVICE_ATTR(thermal_psu2,	S_IRUGO,	show_thermal, 0, 6);

static SENSOR_DEVICE_ATTR(pwm1,		S_IWUSR|S_IRUGO,show_pwm, set_pwm, PWM_OFFSET+0);
static SENSOR_DEVICE_ATTR(pwm2,		S_IWUSR|S_IRUGO,show_pwm, set_pwm, PWM_OFFSET+1);
static SENSOR_DEVICE_ATTR(pwm3,		S_IWUSR|S_IRUGO,show_pwm, set_pwm, PWM_OFFSET+2);
static SENSOR_DEVICE_ATTR(pwm4,		S_IWUSR|S_IRUGO,show_pwm, set_pwm, PWM_OFFSET+3);
static SENSOR_DEVICE_ATTR(pwm_psu1,	S_IWUSR|S_IRUGO,show_pwm, set_pwm, PWM_PSU_OFFSET+0);
static SENSOR_DEVICE_ATTR(pwm_psu2,	S_IWUSR|S_IRUGO,show_pwm, set_pwm, PWM_PSU_OFFSET+1);

static SENSOR_DEVICE_ATTR(psu0,  S_IRUGO,		show_psu_st, 0, 0);
static SENSOR_DEVICE_ATTR(psu1,  S_IRUGO,		show_psu_st, 0, 1);

static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO,		show_rpm, 0, 0*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO,		show_rpm, 0, 1*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO,		show_rpm, 0, 2*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO,		show_rpm, 0, 3*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO,		show_rpm, 0, 4*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO,		show_rpm, 0, 5*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO,		show_rpm, 0, 6*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO,		show_rpm, 0, 7*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(rpm_psu1, S_IRUGO,		show_rpm, 0, 8*2  + RPM_OFFSET);
static SENSOR_DEVICE_ATTR(rpm_psu2, S_IRUGO,		show_rpm, 0, 9*2  + RPM_OFFSET);

static SENSOR_DEVICE_ATTR(switch_tmp, S_IWUSR|S_IRUGO,	show_switch_tmp,	set_switch_tmp, 0);

static SENSOR_DEVICE_ATTR(diag, S_IWUSR|S_IRUGO,	show_diag,		set_diag, 0);
static SENSOR_DEVICE_ATTR(version, S_IRUGO,		show_version,		0, 0);

static SENSOR_DEVICE_ATTR(fan_led_grn1, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 0);
static SENSOR_DEVICE_ATTR(fan_led_grn2, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 1);
static SENSOR_DEVICE_ATTR(fan_led_grn3, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 2);
static SENSOR_DEVICE_ATTR(fan_led_grn4, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 3);
static SENSOR_DEVICE_ATTR(fan_led_red1, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 4);
static SENSOR_DEVICE_ATTR(fan_led_red2, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 5);
static SENSOR_DEVICE_ATTR(fan_led_red3, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 6);
static SENSOR_DEVICE_ATTR(fan_led_red4, S_IWUSR|S_IRUGO,show_fan_led,	set_fan_led, 7);

static SENSOR_DEVICE_ATTR(fan_gpi,   S_IRUGO,		show_value8,   0, FAN_GPI_OFFSET);
static SENSOR_DEVICE_ATTR(fan1_type, S_IRUGO,		show_fan_type, 0, 0);
static SENSOR_DEVICE_ATTR(fan2_type, S_IRUGO,		show_fan_type, 0, 1);
static SENSOR_DEVICE_ATTR(fan3_type, S_IRUGO,		show_fan_type, 0, 2);
static SENSOR_DEVICE_ATTR(fan4_type, S_IRUGO,		show_fan_type, 0, 3);

static SENSOR_DEVICE_ATTR(psu1_vin,      S_IRUGO,	show_psu, 0, (0<<16) | (2<<8) | PMBUS_READ_VIN);
static SENSOR_DEVICE_ATTR(psu1_vout,     S_IRUGO,	show_psu, 0, (0<<16) | (2<<8) | PMBUS_READ_VOUT);
static SENSOR_DEVICE_ATTR(psu1_iin,      S_IRUGO,	show_psu, 0, (0<<16) | (2<<8) | PMBUS_READ_IIN);
static SENSOR_DEVICE_ATTR(psu1_iout,     S_IRUGO,	show_psu, 0, (0<<16) | (2<<8) | PMBUS_READ_IOUT);
static SENSOR_DEVICE_ATTR(psu1_pin,      S_IRUGO,	show_psu, 0, (0<<16) | (2<<8) | PMBUS_READ_PIN);
static SENSOR_DEVICE_ATTR(psu1_pout,     S_IRUGO,	show_psu, 0, (0<<16) | (2<<8) | PMBUS_READ_POUT);

static SENSOR_DEVICE_ATTR(psu1_vendor,   S_IRUGO,	show_psu, 0, (0<<16) | (0<<8) | PMBUS_MFR_ID);
static SENSOR_DEVICE_ATTR(psu1_model,    S_IRUGO,	show_psu, 0, (0<<16) | (0<<8) | PMBUS_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu1_version,  S_IRUGO,	show_psu, 0, (0<<16) | (0<<8) | PMBUS_MFR_REVISION);
static SENSOR_DEVICE_ATTR(psu1_date,     S_IRUGO,	show_psu, 0, (0<<16) | (0<<8) | PMBUS_MFR_DATE);
static SENSOR_DEVICE_ATTR(psu1_sn,       S_IRUGO,	show_psu, 0, (0<<16) | (0<<8) | PMBUS_MFR_SERIAL);

static SENSOR_DEVICE_ATTR(psu2_vin,      S_IRUGO,	show_psu, 0, (1<<16) | (2<<8) | PMBUS_READ_VIN);
static SENSOR_DEVICE_ATTR(psu2_vout,     S_IRUGO,	show_psu, 0, (1<<16) | (2<<8) | PMBUS_READ_VOUT);
static SENSOR_DEVICE_ATTR(psu2_iin,      S_IRUGO,	show_psu, 0, (1<<16) | (2<<8) | PMBUS_READ_IIN);
static SENSOR_DEVICE_ATTR(psu2_iout,     S_IRUGO,	show_psu, 0, (1<<16) | (2<<8) | PMBUS_READ_IOUT);
static SENSOR_DEVICE_ATTR(psu2_pin,      S_IRUGO,	show_psu, 0, (1<<16) | (2<<8) | PMBUS_READ_PIN);
static SENSOR_DEVICE_ATTR(psu2_pout,     S_IRUGO,	show_psu, 0, (1<<16) | (2<<8) | PMBUS_READ_POUT);

static SENSOR_DEVICE_ATTR(psu2_vendor,   S_IRUGO,	show_psu, 0, (1<<16) | (0<<8) | PMBUS_MFR_ID);
static SENSOR_DEVICE_ATTR(psu2_model,    S_IRUGO,	show_psu, 0, (1<<16) | (0<<8) | PMBUS_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu2_version,  S_IRUGO,	show_psu, 0, (1<<16) | (0<<8) | PMBUS_MFR_REVISION);
static SENSOR_DEVICE_ATTR(psu2_date,     S_IRUGO,	show_psu, 0, (1<<16) | (0<<8) | PMBUS_MFR_DATE);
static SENSOR_DEVICE_ATTR(psu2_sn,       S_IRUGO,	show_psu, 0, (1<<16) | (0<<8) | PMBUS_MFR_SERIAL);

static SENSOR_DEVICE_ATTR(psu1_model2,   S_IRUGO,	show_psu1_model, 0, (1<<16) | (0<<8) | PMBUS_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu1_sn2,      S_IRUGO,	show_psu1_sn,    0, (1<<16) | (0<<8) | PMBUS_MFR_SERIAL);
static SENSOR_DEVICE_ATTR(psu2_model2,   S_IRUGO,	show_psu2_model, 0, (1<<16) | (0<<8) | PMBUS_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu2_sn2,      S_IRUGO,	show_psu2_sn,    0, (1<<16) | (0<<8) | PMBUS_MFR_SERIAL);
		
static SENSOR_DEVICE_ATTR(psoc_psu1_vin,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu1_vin));
static SENSOR_DEVICE_ATTR(psoc_psu1_vout,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu1_vout));
static SENSOR_DEVICE_ATTR(psoc_psu1_iin,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu1_iin));
static SENSOR_DEVICE_ATTR(psoc_psu1_iout,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu1_iout));
static SENSOR_DEVICE_ATTR(psoc_psu1_pin,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu1_pin));
static SENSOR_DEVICE_ATTR(psoc_psu1_pout,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu1_pout));


static SENSOR_DEVICE_ATTR(psoc_psu2_vin,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu2_vin));
static SENSOR_DEVICE_ATTR(psoc_psu2_vout,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu2_vout));
static SENSOR_DEVICE_ATTR(psoc_psu2_iin,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu2_iin));
static SENSOR_DEVICE_ATTR(psoc_psu2_iout,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu2_iout));
static SENSOR_DEVICE_ATTR(psoc_psu2_pin,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu2_pin));
static SENSOR_DEVICE_ATTR(psoc_psu2_pout,	S_IRUGO,	show_psu_psoc, 0, PSOC_PSU_OFF(psu2_pout));
			
static struct attribute *psoc_attributes[] = {
    //thermal
	&sensor_dev_attr_temp1_input.dev_attr.attr,
	&sensor_dev_attr_temp2_input.dev_attr.attr,
	&sensor_dev_attr_temp3_input.dev_attr.attr,
	&sensor_dev_attr_temp4_input.dev_attr.attr,
	&sensor_dev_attr_temp5_input.dev_attr.attr,
	
	&sensor_dev_attr_thermal_psu1.dev_attr.attr,
	&sensor_dev_attr_thermal_psu2.dev_attr.attr,


    //pwm
	&sensor_dev_attr_pwm1.dev_attr.attr,
	&sensor_dev_attr_pwm2.dev_attr.attr,
	&sensor_dev_attr_pwm3.dev_attr.attr,
	&sensor_dev_attr_pwm4.dev_attr.attr,
	&sensor_dev_attr_pwm_psu1.dev_attr.attr,
	&sensor_dev_attr_pwm_psu2.dev_attr.attr,
	
	//rpm
	&sensor_dev_attr_fan1_input.dev_attr.attr,
	&sensor_dev_attr_fan2_input.dev_attr.attr,
	&sensor_dev_attr_fan3_input.dev_attr.attr,
	&sensor_dev_attr_fan4_input.dev_attr.attr,
	&sensor_dev_attr_fan5_input.dev_attr.attr,
	&sensor_dev_attr_fan6_input.dev_attr.attr,
	&sensor_dev_attr_fan7_input.dev_attr.attr,
	&sensor_dev_attr_fan8_input.dev_attr.attr,
	
	&sensor_dev_attr_rpm_psu1.dev_attr.attr,
	&sensor_dev_attr_rpm_psu2.dev_attr.attr,
    
    //switch temperature
	&sensor_dev_attr_switch_tmp.dev_attr.attr,

    //diag flag
	&sensor_dev_attr_diag.dev_attr.attr,
	
	//version
	&sensor_dev_attr_version.dev_attr.attr,
	
	//fan led 
	&sensor_dev_attr_fan_led_grn1.dev_attr.attr,
	&sensor_dev_attr_fan_led_grn2.dev_attr.attr,
	&sensor_dev_attr_fan_led_grn3.dev_attr.attr,
	&sensor_dev_attr_fan_led_grn4.dev_attr.attr,
	&sensor_dev_attr_fan_led_red1.dev_attr.attr,
	&sensor_dev_attr_fan_led_red2.dev_attr.attr,
	&sensor_dev_attr_fan_led_red3.dev_attr.attr,
	&sensor_dev_attr_fan_led_red4.dev_attr.attr,

	//fan GPI 
	&sensor_dev_attr_fan_gpi.dev_attr.attr,

	//fan type
	&sensor_dev_attr_fan1_type.dev_attr.attr,
	&sensor_dev_attr_fan2_type.dev_attr.attr,
	&sensor_dev_attr_fan3_type.dev_attr.attr,
	&sensor_dev_attr_fan4_type.dev_attr.attr,
	
	//psu
	&sensor_dev_attr_psu1_vin.dev_attr.attr,
	&sensor_dev_attr_psu1_vout.dev_attr.attr,
	&sensor_dev_attr_psu1_iin.dev_attr.attr,
	&sensor_dev_attr_psu1_iout.dev_attr.attr,
	&sensor_dev_attr_psu1_pin.dev_attr.attr,
	&sensor_dev_attr_psu1_pout.dev_attr.attr,
	&sensor_dev_attr_psu2_vin.dev_attr.attr,
	&sensor_dev_attr_psu2_vout.dev_attr.attr,
	&sensor_dev_attr_psu2_iin.dev_attr.attr,
	&sensor_dev_attr_psu2_iout.dev_attr.attr,
	&sensor_dev_attr_psu2_pin.dev_attr.attr,
	&sensor_dev_attr_psu2_pout.dev_attr.attr,

	&sensor_dev_attr_psu1_vendor.dev_attr.attr,
	&sensor_dev_attr_psu1_model.dev_attr.attr,
	&sensor_dev_attr_psu1_version.dev_attr.attr,
	&sensor_dev_attr_psu1_date.dev_attr.attr,
	&sensor_dev_attr_psu1_sn.dev_attr.attr,
	&sensor_dev_attr_psu2_vendor.dev_attr.attr,
	&sensor_dev_attr_psu2_model.dev_attr.attr,
	&sensor_dev_attr_psu2_version.dev_attr.attr,
	&sensor_dev_attr_psu2_date.dev_attr.attr,
	&sensor_dev_attr_psu2_sn.dev_attr.attr,

	&sensor_dev_attr_psu1_model2.dev_attr.attr,
	&sensor_dev_attr_psu1_sn2.dev_attr.attr,
	&sensor_dev_attr_psu2_model2.dev_attr.attr,
	&sensor_dev_attr_psu2_sn2.dev_attr.attr,

	&sensor_dev_attr_psu0.dev_attr.attr,
	&sensor_dev_attr_psu1.dev_attr.attr,

	//psu_psoc, new added on psoc 1.9
	&sensor_dev_attr_psoc_psu1_vin.dev_attr.attr,
	&sensor_dev_attr_psoc_psu1_vout.dev_attr.attr,
	&sensor_dev_attr_psoc_psu1_iin.dev_attr.attr,
	&sensor_dev_attr_psoc_psu1_iout.dev_attr.attr,
	&sensor_dev_attr_psoc_psu1_pin.dev_attr.attr,
	&sensor_dev_attr_psoc_psu1_pout.dev_attr.attr,
	&sensor_dev_attr_psoc_psu2_vin.dev_attr.attr,
	&sensor_dev_attr_psoc_psu2_vout.dev_attr.attr,
	&sensor_dev_attr_psoc_psu2_iin.dev_attr.attr,
	&sensor_dev_attr_psoc_psu2_iout.dev_attr.attr,
	&sensor_dev_attr_psoc_psu2_pin.dev_attr.attr,
	&sensor_dev_attr_psoc_psu2_pout.dev_attr.attr,

	NULL
};

static const struct attribute_group psoc_group = {
	.attrs = psoc_attributes,
};

/*-----------------------------------------------------------------------*/

/* device probe and removal */

static int
psoc_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct psoc_data *data;
	int status;

	if (!i2c_check_functionality(client->adapter,
			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
		return -EIO;

	data = kzalloc(sizeof(struct psoc_data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	i2c_set_clientdata(client, data);
	mutex_init(&data->update_lock);
	data->diag    = 0;

	mutex_init(&psu_data_lock);

	/* Register sysfs hooks */
	status = sysfs_create_group(&client->dev.kobj, &psoc_group);
	if (status)
		goto exit_free;

	data->hwmon_dev = hwmon_device_register(&client->dev);
	if (IS_ERR(data->hwmon_dev)) {
		status = PTR_ERR(data->hwmon_dev);
		goto exit_remove;
	}

	dev_info(&client->dev, "%s: sensor '%s'\n",
		 dev_name(data->hwmon_dev), client->name);

	psoc_led_client_dev = &client->dev;

	return 0;

exit_remove:
	sysfs_remove_group(&client->dev.kobj, &psoc_group);
exit_free:
	i2c_set_clientdata(client, NULL);
	kfree(data);
	psoc_led_client_dev = NULL;
	return status;
}

static int psoc_remove(struct i2c_client *client)
{
	struct psoc_data *data = i2c_get_clientdata(client);

	hwmon_device_unregister(data->hwmon_dev);
	sysfs_remove_group(&client->dev.kobj, &psoc_group);
	i2c_set_clientdata(client, NULL);
	kfree(data);
	psoc_led_client_dev = NULL;
	return 0;
}

static const struct i2c_device_id psoc_ids[] = {
	{ "inv_psoc", 0, },
	{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, psoc_ids);

static struct i2c_driver psoc_driver = {
	.class		= I2C_CLASS_HWMON,
	.driver = {
		.name	= "inv_psoc",
	},
	.probe		= psoc_probe,
	.remove		= psoc_remove,
	.id_table	= psoc_ids,
};

/*-----------------------------------------------------------------------*/

/* module glue */

static int __init inv_psoc_init(void)
{
	return i2c_add_driver(&psoc_driver);
}

static void __exit inv_psoc_exit(void)
{
	i2c_del_driver(&psoc_driver);
}

MODULE_AUTHOR("eddie.lan <eddie.lan@inventec>");
MODULE_DESCRIPTION("inv psoc driver");
MODULE_LICENSE("GPL");

module_init(inv_psoc_init);
module_exit(inv_psoc_exit);
