自己写的双电池IC driver(linux 框架下driver部分)

来源:互联网 发布:.net和php哪个好一些 编辑:程序博客网 时间:2024/06/05 16:38
/* 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&REG_STATUS_BI)>>7);
    chip->g_stDualBatInfo.BATB_ID = ((Status_Reg&REG_STATUS_AI)>>6);
    chip->g_stDualBatInfo.BAT_Status = ((Status_Reg&REG_STATUS_BS)>>4);
    
    chip->g_stDualBatInfo.BATB_VB = ((Status_Reg&REG_STATUS_BVD)>>2);
    chip->g_stDualBatInfo.BATA_VA = ((Status_Reg&REG_STATUS_AVD));   

    chip->g_stDualBatInfo.BATA_PreCharge = ((Config_Reg&REG_CONFIG_SB)>>7);
    chip->g_stDualBatInfo.BATB_PreCharge = ((Config_Reg&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");