/* Copyright (c) 2011-2012, CAll rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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/delay.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/sn8200.h>
#define REG_STATUS_BI 0x80
#define REG_STATUS_AI 0x40
#define REG_STATUS_BS 0x30
#define REG_STATUS_BVD 0x0C
#define REG_STATUS_AVD 0x03
#define REG_CONFIG_SB 0x80
#define REG_CONFIG_SA 0x40
typedef struct _stDUAL_BAT_INFO
{
unsigned char BATA_ID;
unsigned char BATB_ID;
unsigned char BAT_Status;
unsigned char BATA_VA;
unsigned char BATB_VB;
unsigned int BATA_Voltage;
unsigned int BATB_Voltage;
unsigned char BATA_PreCharge;
unsigned char BATB_PreCharge;
} SN_DUAL_BAT_INFO;
static unsigned char g_SN_status = 0;
struct sn8200_chip {
struct i2c_client *sn8200_client;
static SN_DUAL_BAT_INFO g_stDualBatInfo;
};
unsigned int Status_Reg,Config_Reg;
Status_Reg = sn8200_i2c_read(0x00);
Config_Reg = sn8200_i2c_read(0x01);
void SN_GetBatStatus(void)
{
struct sn8200_chip *chip;
unsigned int Status_Reg,Config_Reg;
uint32 voltage;
double adc_value;
Status_Reg = sn8200_i2c_read(0x00);
Config_Reg = sn8200_i2c_read(0x01);
chip->g_stDualBatInfo.BATA_ID = ((Status_Reg®_STATUS_BI)>>7);
chip->g_stDualBatInfo.BATB_ID = ((Status_Reg®_STATUS_AI)>>6);
chip->g_stDualBatInfo.BAT_Status = ((Status_Reg®_STATUS_BS)>>4);
chip->g_stDualBatInfo.BATB_VB = ((Status_Reg®_STATUS_BVD)>>2);
chip->g_stDualBatInfo.BATA_VA = ((Status_Reg®_STATUS_AVD));
chip->g_stDualBatInfo.BATA_PreCharge = ((Config_Reg®_CONFIG_SB)>>7);
chip->g_stDualBatInfo.BATB_PreCharge = ((Config_Reg®_CONFIG_SA)>>6);
}
static int sn8200_i2c_rxdata(unsigned short saddr,
unsigned char *rxdata, int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = 1,
.buf = rxdata,
},
};
if (i2c_transfer(sn8200_client->adapter, msgs, 2) < 0) {
CDBG("sn8200_i2c_rxdata failed!\n");
return -EIO;
}
return 0;
}
static int32_t sn8200_i2c_txdata(unsigned short saddr,
unsigned char *txdata, int length)
{
struct i2c_msg msg[] = {
{
.addr = saddr,
.flags = 0,
.len = 2,
.buf = txdata,
},
};
if (i2c_transfer(sn8200_client->adapter, msg, 1) < 0) {
CDBG("sn8200_i2c_txdata faild 0x%x\n", sn8200_client->addr);
return -EIO;
}
return 0;
}
static int32_t sn8200_i2c_read(uint8_t raddr,
uint8_t *rdata, int rlen)
{
int32_t rc = 0;
unsigned char buf[1];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = raddr;
rc = sn8200_i2c_rxdata(sn8200_client->addr >> 1, buf, rlen);
if (rc < 0) {
CDBG("sn8200_i2c_read 0x%x failed!\n", raddr);
return rc;
}
*rdata = buf[0];
return rc;
}
static int32_t sn8200_i2c_write(uint8_t waddr, uint8_t bdata)
{
int32_t rc = -EFAULT;
unsigned char buf[2];
memset(buf, 0, sizeof(buf));
buf[0] = waddr;
buf[1] = bdata;
printk("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
rc = sn8200_i2c_txdata(sn8200_client->addr >> 1, buf, 2);
if (rc < 0)
CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
waddr, bdata);
return rc;
}
static const struct i2c_device_id sn8200_i2c_id[] = {
{"sn8200", 0},
{ }
};
void SN_ReConfig(unsigned char op)
{
switch (op){
case 1:
/*PS(bit 4 bit 5) set 00 auto supply*/
g_SN_status = Config_Reg&(~(0x01<<4));
g_SN_status = g_SN_status&(~(0x01<<5));
sn8200_i2c_write(0x01,g_SN_status);
break;
case 2:
/*PS(bit 4 bit 5) set 01 A-bat supply*/
g_SN_status = Config_Reg|(0x01<<4);
g_SN_status = g_SN_status&(~(0x01<<5));
sn8200_i2c_write(0x01,g_SN_status);
break;
case 3:
/*PS(bit 4 bit 5) set 10 B-bat supply*/
g_SN_status = Config_Reg&(~(0x01<<4));
g_SN_status = g_SN_status|(0x01<<5);
sn8200_i2c_write(0x01,g_SN_status);
break;
}
}
void SN_HW_Init(void)
{
SN_GetBatStatus();
if (chip->g_stDualBatInfo.BATA_ID==0 && chip->g_stDualBatInfo.BATB_ID==0)
{
if (chip->g_stDualBatInfo.BAT_Status == 0 )//A supply
{
if (chip->g_stDualBatInfo.BATB_VB != 0) //Vb>=Vth2 B supply
{
SN_ReConfig(3);
}
else
{
SN_ReConfig(2); //A supply
}
}
if ( chip->g_stDualBatInfo.BAT_Status == 1) //B supply
{
if (chip->g_stDualBatInfo.BATA_VB== 0) //B low
{
SN_ReConfig(2);//change to A
}
else
{
SN_ReConfig(3);//B supply
}
}
}
else if (chip->g_stDualBatInfo.BATA_ID==0)
{
SN_ReConfig(2); //A supply
}
else
{
SN_ReConfig(3) //B supply
}
}
static int sn8200_init_hw(struct sn8200_chip *chip,
struct sn8200_platform_data *pdata)
{
int err = 0;
if (pdata->reset_during_probe) {
err = sn8200_reset(chip);
if (err < 0)
return err;
}
err = sn8200_i2c_write(chip->client,
chip->dev_cfg->reg_misc,
0x01);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_pullup,
pdata->io_pullup_ena);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_pulldn,
pdata->io_pulldn_ena);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_drain,
pdata->io_open_drain_ena);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_polarity,
pdata->io_polarity);
if (err < 0)
return err;
if (pdata->oscio_is_gpo)
sn8200_set_oscio(chip, 0);
return err;
}
//get vbatt_mv
static int pm8058_get_battery_mvolts(void)
{
int vbatt_mv;
vbatt_mv = batt_read_adc(CHANNEL_ADC_VBATT, NULL);
pr_debug("%s: vbatt_mv is %d\n", __func__, vbatt_mv);
if (vbatt_mv > 0)
return vbatt_mv;
}
static int sn8200_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct sn8200_platform_data *pdata;
struct sn8200_data *chip;
int rc = 0;
printk("sn8200_i2c_probe called!\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
CDBG("i2c_check_functionality failed\n");
goto probe_failure;
}
/* Allocate memory for driver data */
data = kzalloc(sizeof(struct sn8200_data), GFP_KERNEL);
if (!data) {
printk(KERN_ERR "data8975 data8975_probe: memory allocation failed.\n");
err = -ENOMEM;
goto exit1;
}
//INIT_WORK(&data->work, data8975_work_func);
i2c_set_clientdata(client, data);
/* Check platform data*/
if (client->dev.platform_data == NULL) {
printk(KERN_ERR "data8975 data8975_probe: platform data is NULL\n");
err = -ENOMEM;
goto exit2;
}
/* Copy to global variable */
pdata = client->dev.platform_data;
sn8200_client = client;
rc = sn8200_init_hw(chip, pdata);
if (rc < 0)
printk("sn8200_init_hw initlised failed!");
/* IRQ */
//err = request_irq(client->irq, data8975_interrupt, IRQ_TYPE_EDGE_RISING,
"data8975_DRDY", data);
//if (err < 0) {
// printk(KERN_ERR "data8975 data8975_probe: request irq failed\n");
//}
//sn8200_init_client(client);
printk("sn8200_i2c_probe success! rc = %d\n", rc);
return 0;
}
}
static int __exit sn8200_i2c_remove(struct i2c_client *client)
{
struct sn8200_chip *data = i2c_get_clientdata(client);
free_irq(client->irq, data);
sn8200_client = NULL;
kfree(data);
return 0;
}
static struct i2c_driver sn8200_i2c_driver = {
.id_table = sn8200_i2c_id,
.probe = sn8200_i2c_probe,
.remove = __exit_p(sn8200_i2c_remove),
.driver = {
.name = "sn8200",
},
};
static int __init sn8200_init(void)
{
printk("sn8200 initlised successed");
return i2c_add_driver(&sn8200_i2c_driver);
}
module_init(sn8200_init);
MODULE_DESCRIPTION("sn8200 sensor driver--author w");
MODULE_LICENSE("GPL v2");
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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/delay.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/sn8200.h>
#define REG_STATUS_BI 0x80
#define REG_STATUS_AI 0x40
#define REG_STATUS_BS 0x30
#define REG_STATUS_BVD 0x0C
#define REG_STATUS_AVD 0x03
#define REG_CONFIG_SB 0x80
#define REG_CONFIG_SA 0x40
typedef struct _stDUAL_BAT_INFO
{
unsigned char BATA_ID;
unsigned char BATB_ID;
unsigned char BAT_Status;
unsigned char BATA_VA;
unsigned char BATB_VB;
unsigned int BATA_Voltage;
unsigned int BATB_Voltage;
unsigned char BATA_PreCharge;
unsigned char BATB_PreCharge;
} SN_DUAL_BAT_INFO;
static unsigned char g_SN_status = 0;
struct sn8200_chip {
struct i2c_client *sn8200_client;
static SN_DUAL_BAT_INFO g_stDualBatInfo;
};
unsigned int Status_Reg,Config_Reg;
Status_Reg = sn8200_i2c_read(0x00);
Config_Reg = sn8200_i2c_read(0x01);
void SN_GetBatStatus(void)
{
struct sn8200_chip *chip;
unsigned int Status_Reg,Config_Reg;
uint32 voltage;
double adc_value;
Status_Reg = sn8200_i2c_read(0x00);
Config_Reg = sn8200_i2c_read(0x01);
chip->g_stDualBatInfo.BATA_ID = ((Status_Reg®_STATUS_BI)>>7);
chip->g_stDualBatInfo.BATB_ID = ((Status_Reg®_STATUS_AI)>>6);
chip->g_stDualBatInfo.BAT_Status = ((Status_Reg®_STATUS_BS)>>4);
chip->g_stDualBatInfo.BATB_VB = ((Status_Reg®_STATUS_BVD)>>2);
chip->g_stDualBatInfo.BATA_VA = ((Status_Reg®_STATUS_AVD));
chip->g_stDualBatInfo.BATA_PreCharge = ((Config_Reg®_CONFIG_SB)>>7);
chip->g_stDualBatInfo.BATB_PreCharge = ((Config_Reg®_CONFIG_SA)>>6);
}
static int sn8200_i2c_rxdata(unsigned short saddr,
unsigned char *rxdata, int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = 1,
.buf = rxdata,
},
};
if (i2c_transfer(sn8200_client->adapter, msgs, 2) < 0) {
CDBG("sn8200_i2c_rxdata failed!\n");
return -EIO;
}
return 0;
}
static int32_t sn8200_i2c_txdata(unsigned short saddr,
unsigned char *txdata, int length)
{
struct i2c_msg msg[] = {
{
.addr = saddr,
.flags = 0,
.len = 2,
.buf = txdata,
},
};
if (i2c_transfer(sn8200_client->adapter, msg, 1) < 0) {
CDBG("sn8200_i2c_txdata faild 0x%x\n", sn8200_client->addr);
return -EIO;
}
return 0;
}
static int32_t sn8200_i2c_read(uint8_t raddr,
uint8_t *rdata, int rlen)
{
int32_t rc = 0;
unsigned char buf[1];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = raddr;
rc = sn8200_i2c_rxdata(sn8200_client->addr >> 1, buf, rlen);
if (rc < 0) {
CDBG("sn8200_i2c_read 0x%x failed!\n", raddr);
return rc;
}
*rdata = buf[0];
return rc;
}
static int32_t sn8200_i2c_write(uint8_t waddr, uint8_t bdata)
{
int32_t rc = -EFAULT;
unsigned char buf[2];
memset(buf, 0, sizeof(buf));
buf[0] = waddr;
buf[1] = bdata;
printk("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
rc = sn8200_i2c_txdata(sn8200_client->addr >> 1, buf, 2);
if (rc < 0)
CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
waddr, bdata);
return rc;
}
static const struct i2c_device_id sn8200_i2c_id[] = {
{"sn8200", 0},
{ }
};
void SN_ReConfig(unsigned char op)
{
switch (op){
case 1:
/*PS(bit 4 bit 5) set 00 auto supply*/
g_SN_status = Config_Reg&(~(0x01<<4));
g_SN_status = g_SN_status&(~(0x01<<5));
sn8200_i2c_write(0x01,g_SN_status);
break;
case 2:
/*PS(bit 4 bit 5) set 01 A-bat supply*/
g_SN_status = Config_Reg|(0x01<<4);
g_SN_status = g_SN_status&(~(0x01<<5));
sn8200_i2c_write(0x01,g_SN_status);
break;
case 3:
/*PS(bit 4 bit 5) set 10 B-bat supply*/
g_SN_status = Config_Reg&(~(0x01<<4));
g_SN_status = g_SN_status|(0x01<<5);
sn8200_i2c_write(0x01,g_SN_status);
break;
}
}
void SN_HW_Init(void)
{
SN_GetBatStatus();
if (chip->g_stDualBatInfo.BATA_ID==0 && chip->g_stDualBatInfo.BATB_ID==0)
{
if (chip->g_stDualBatInfo.BAT_Status == 0 )//A supply
{
if (chip->g_stDualBatInfo.BATB_VB != 0) //Vb>=Vth2 B supply
{
SN_ReConfig(3);
}
else
{
SN_ReConfig(2); //A supply
}
}
if ( chip->g_stDualBatInfo.BAT_Status == 1) //B supply
{
if (chip->g_stDualBatInfo.BATA_VB== 0) //B low
{
SN_ReConfig(2);//change to A
}
else
{
SN_ReConfig(3);//B supply
}
}
}
else if (chip->g_stDualBatInfo.BATA_ID==0)
{
SN_ReConfig(2); //A supply
}
else
{
SN_ReConfig(3) //B supply
}
}
static int sn8200_init_hw(struct sn8200_chip *chip,
struct sn8200_platform_data *pdata)
{
int err = 0;
if (pdata->reset_during_probe) {
err = sn8200_reset(chip);
if (err < 0)
return err;
}
err = sn8200_i2c_write(chip->client,
chip->dev_cfg->reg_misc,
0x01);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_pullup,
pdata->io_pullup_ena);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_pulldn,
pdata->io_pulldn_ena);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_drain,
pdata->io_open_drain_ena);
if (err < 0)
return err;
err = sn8200_init_io(chip, chip->dev_cfg->reg_polarity,
pdata->io_polarity);
if (err < 0)
return err;
if (pdata->oscio_is_gpo)
sn8200_set_oscio(chip, 0);
return err;
}
//get vbatt_mv
static int pm8058_get_battery_mvolts(void)
{
int vbatt_mv;
vbatt_mv = batt_read_adc(CHANNEL_ADC_VBATT, NULL);
pr_debug("%s: vbatt_mv is %d\n", __func__, vbatt_mv);
if (vbatt_mv > 0)
return vbatt_mv;
}
static int sn8200_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct sn8200_platform_data *pdata;
struct sn8200_data *chip;
int rc = 0;
printk("sn8200_i2c_probe called!\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
CDBG("i2c_check_functionality failed\n");
goto probe_failure;
}
/* Allocate memory for driver data */
data = kzalloc(sizeof(struct sn8200_data), GFP_KERNEL);
if (!data) {
printk(KERN_ERR "data8975 data8975_probe: memory allocation failed.\n");
err = -ENOMEM;
goto exit1;
}
//INIT_WORK(&data->work, data8975_work_func);
i2c_set_clientdata(client, data);
/* Check platform data*/
if (client->dev.platform_data == NULL) {
printk(KERN_ERR "data8975 data8975_probe: platform data is NULL\n");
err = -ENOMEM;
goto exit2;
}
/* Copy to global variable */
pdata = client->dev.platform_data;
sn8200_client = client;
rc = sn8200_init_hw(chip, pdata);
if (rc < 0)
printk("sn8200_init_hw initlised failed!");
/* IRQ */
//err = request_irq(client->irq, data8975_interrupt, IRQ_TYPE_EDGE_RISING,
"data8975_DRDY", data);
//if (err < 0) {
// printk(KERN_ERR "data8975 data8975_probe: request irq failed\n");
//}
//sn8200_init_client(client);
printk("sn8200_i2c_probe success! rc = %d\n", rc);
return 0;
}
}
static int __exit sn8200_i2c_remove(struct i2c_client *client)
{
struct sn8200_chip *data = i2c_get_clientdata(client);
free_irq(client->irq, data);
sn8200_client = NULL;
kfree(data);
return 0;
}
static struct i2c_driver sn8200_i2c_driver = {
.id_table = sn8200_i2c_id,
.probe = sn8200_i2c_probe,
.remove = __exit_p(sn8200_i2c_remove),
.driver = {
.name = "sn8200",
},
};
static int __init sn8200_init(void)
{
printk("sn8200 initlised successed");
return i2c_add_driver(&sn8200_i2c_driver);
}
module_init(sn8200_init);
MODULE_DESCRIPTION("sn8200 sensor driver--author w");
MODULE_LICENSE("GPL v2");