omap-tps65010.c

来自「嵌入式系统中的,TPS65010 驱动程序, IIC 接口」· C语言 代码 · 共 505 行

C
505
字号
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/proc_fs.h>
#include <linux/i2c.h>

#include <asm/io.h>
#include <asm/arch/pm.h>

#include "omap-tps65010.h"


#if 1
#define DBGPRINT(fmt, args...)  printk(fmt, ##args)
#else
#define DBGPRINT(fmt, args...)
#endif


extern void tps_deep_sleep(void);


#define TPS_I2C_SLAVE_ADDR          0x48


#define TPS_VDCDC1_REG              0x0c

#define TPS_LP_BIT                  0x08

#define TPS_SET_LP_BIT(v)           ( v |= TPS_LP_BIT )
#define TPS_CLR_LP_BIT(v)           ( v &= ~(TPS_LP_BIT) )


#define TPS_LED_REG                 0x10

#define TPS_KB_LED_BIT              0x01
#define TPS_MAIN_LED_BIT            0x04
#define TPS_SUB_LED_BIT             0x02
#define TPS_ALL_LED_BIT              ( TPS_KB_LED_BIT | TPS_MAIN_LED_BIT| TPS_SUB_LED_BIT )

#define TPS_SET_KB_LED_BIT(v)       ( v |= TPS_KB_LED_BIT )
#define TPS_CLR_KB_LED_BIT(v)       ( v &= ~(TPS_KB_LED_BIT) )
#define TPS_GET_KB_LED_BIT(v)       ( (v & TPS_KB_LED_BIT) == TPS_KB_LED_BIT )

#define TPS_SET_MAIN_LED_BIT(v)     ( v |= TPS_MAIN_LED_BIT )
#define TPS_CLR_MAIN_LED_BIT(v)     ( v &= ~(TPS_MAIN_LED_BIT) )
#define TPS_GET_MAIN_LED_BIT(v)     ( (v & TPS_MAIN_LED_BIT) == TPS_MAIN_LED_BIT )

#define TPS_SET_SUB_LED_BIT(v)      ( v |= TPS_SUB_LED_BIT )
#define TPS_CLR_SUB_LED_BIT(v)      ( v &= ~(TPS_SUB_LED_BIT) )
#define TPS_GET_SUB_LED_BIT(v)      ( (v & TPS_SUB_LED_BIT) == TPS_SUB_LED_BIT )

#define TPS_SET_ALL_LED_BIT(v)      ( v |= TPS_ALL_LED_BIT )
#define TPS_CLR_ALL_LED_BIT(v)      ( v &= ~(TPS_ALL_LED_BIT) )


#define TPS_VIB_REG                 0x0d

#define TPS_VIB_BIT                 0x02

#define TPS_SET_VIB_BIT(v)          ( v |= TPS_VIB_BIT )
#define TPS_CLR_VIB_BIT(v)          ( v &= ~(TPS_VIB_BIT) )
#define TPS_GET_VIB_BIT(v)          ( (v & TPS_VIB_BIT) == TPS_VIB_BIT )


#define TPS_QS6400_REG              0x10

#define TPS_QS6400_BIT              0x08

#define TPS_SET_QS6400_BIT(v)       ( v |= TPS_QS6400_BIT )
#define TPS_CLR_QS6400_BIT(v)       ( v &= ~(TPS_QS6400_BIT) )


static int tps_probe(struct i2c_adapter *adap);
static int tps_detach(struct i2c_client *client);

static struct i2c_driver  tps_driver = 
{
    .name             = "OMAP1510+TPS",
    .id               = I2C_DRIVERID_EXP0,
    .flags            = I2C_DF_NOTIFY,
    .attach_adapter	  = tps_probe,
    .detach_client    = tps_detach,
};

static struct i2c_client  tps_client =
{
    .name       = "OMAP1510+TPS",
    .id         = -1,
    .adapter    = NULL,
    .driver	    = &tps_driver
};

static unsigned short  normal_addr[] = { TPS_I2C_SLAVE_ADDR, I2C_CLIENT_END };
static unsigned short  ignore[] = { I2C_CLIENT_END };

static struct i2c_client_address_data  addr_data =
{
    .normal_i2c             = normal_addr,
    .normal_i2c_range       = ignore,
    .probe                  = ignore,
    .probe_range            = ignore,
    .ignore                 = ignore,
    .ignore_range           = ignore,
    .force                  = ignore,
};


static int tps_attach(struct i2c_adapter *adap, int addr,
			unsigned short flags, int kind)
{
    u8  status;

    DBGPRINT("%s\n", __FUNCTION__);

    printk(KERN_INFO "TPS found @ 0x%x by %s\n", addr, adap->name);

    tps_client.adapter = adap;
    tps_client.addr = addr;

    i2c_attach_client(&tps_client);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_LED_REG);
    status |= 0xf0;
    i2c_smbus_write_byte_data(&tps_client, TPS_LED_REG, status);

    tps_set_lowpower(1);

    return 0;
}

static int tps_probe(struct i2c_adapter *adap)
{
    DBGPRINT("%s\n", __FUNCTION__);

    return i2c_probe(adap, &addr_data, tps_attach);
}

static int tps_detach(struct i2c_client *client)
{
    DBGPRINT("%s\n", __FUNCTION__);

    i2c_detach_client(client);

    return 0;
}


int tps_set_lowpower(int mode)
{
    u8  vdcdc1;

    DBGPRINT("%s: %d\n", __FUNCTION__, mode);

    vdcdc1 = i2c_smbus_read_byte_data(&tps_client, TPS_VDCDC1_REG);

    if ( mode )
        TPS_SET_LP_BIT(vdcdc1);
    else
        TPS_CLR_LP_BIT(vdcdc1);

    i2c_smbus_write_byte_data(&tps_client, TPS_VDCDC1_REG, vdcdc1);

    return 0;
}

int tps_sleep(int mode)
{
    DBGPRINT("%s: %d\n", __FUNCTION__, mode);

    omap_pm_suspend();

    return 0;
}


int tps_led_on(int led)
{
    u8  status;

    DBGPRINT("%s: %d\n", __FUNCTION__, led);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_LED_REG);

    switch ( led )
    {
        case TPS_ALL_LED:
            TPS_SET_ALL_LED_BIT(status);
            break;

        case TPS_KB_LED:
            TPS_SET_KB_LED_BIT(status);
            break;

        case TPS_MAIN_LED:
            TPS_SET_MAIN_LED_BIT(status);
            break;

        case TPS_SUB_LED:
            TPS_SET_SUB_LED_BIT(status);
            break;

        default:
            printk("%s: bad led number: %d\n", __FUNCTION__, led);
            return -EINVAL;
    }

    i2c_smbus_write_byte_data(&tps_client, TPS_LED_REG, status);

    return 0;
}

int tps_led_off(int led)
{
    u8  status;

    DBGPRINT("%s: %d\n", __FUNCTION__, led);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_LED_REG);

    switch ( led )
    {
        case TPS_ALL_LED:
            TPS_CLR_ALL_LED_BIT(status);
            break;

        case TPS_KB_LED:
            TPS_CLR_KB_LED_BIT(status);
            break;

        case TPS_MAIN_LED:
            TPS_CLR_MAIN_LED_BIT(status);
            break;

        case TPS_SUB_LED:
            TPS_CLR_SUB_LED_BIT(status);
            break;

        default:
            printk("%s: bad led number: %d\n", __FUNCTION__, led);
            return -EINVAL;
    }

    i2c_smbus_write_byte_data(&tps_client, TPS_LED_REG, status);

    return 0;
}

int tps_led_state(int led)
{
    int  ret = 0;
    u8  status;

    DBGPRINT("%s: %d\n", __FUNCTION__, led);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_LED_REG);

    switch ( led )
    {
        case TPS_KB_LED:
            ret = TPS_GET_KB_LED_BIT(status);
            break;

        case TPS_MAIN_LED:
            ret = TPS_GET_MAIN_LED_BIT(status);
            break;

        case TPS_SUB_LED:
            ret = TPS_GET_SUB_LED_BIT(status);
            break;

        default:
            printk("%s: bad led number: %d\n", __FUNCTION__, led);
            return -EINVAL;
    }

    return ret;
}


int tps_vib_cmd(int cmd)
{
    u8  status;

    DBGPRINT("%s: %d\n", __FUNCTION__, cmd);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_VIB_REG);

    if ( cmd == TPS_VIB_RUN )
    {
        TPS_SET_VIB_BIT(status);
    }
    else
    {
        TPS_CLR_VIB_BIT(status);
    }

    i2c_smbus_write_byte_data(&tps_client, TPS_VIB_REG, status);

    return 0;
}

int tps_vib_state(void)
{
    u8  status;

    DBGPRINT("%s\n", __FUNCTION__);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_VIB_REG);

    return TPS_GET_VIB_BIT(status);
}


int tps_qs6400_wake(void)
{
    u8  status;

    DBGPRINT("%s\n", __FUNCTION__);

    status = i2c_smbus_read_byte_data(&tps_client, TPS_QS6400_REG);

    TPS_SET_QS6400_BIT(status);
    i2c_smbus_write_byte_data(&tps_client, TPS_QS6400_REG, status);

    udelay(10);

    TPS_CLR_QS6400_BIT(status);
    i2c_smbus_write_byte_data(&tps_client, TPS_QS6400_REG, status);

    return 0;
}


static int tps_stats(char *buf, char **start, off_t offset,
			int count, int *eof, void *data)
{
    int  len;
    char *  p = buf;

    DBGPRINT("%s\n", __FUNCTION__);

    p += sprintf(p, "TPS info: \n");
    p += sprintf(p, "  keypad led state: %d\n", tps_led_state(TPS_KB_LED));
    p += sprintf(p, "  main led state  : %d\n", tps_led_state(TPS_MAIN_LED));
    p += sprintf(p, "  sub led state   : %d\n", tps_led_state(TPS_SUB_LED));
    p += sprintf(p, "  VIB state       : %d\n", tps_vib_state());
    p += sprintf(p, "  VDCDC1 REG      : 0x%x\n", i2c_smbus_read_byte_data(&tps_client, TPS_VDCDC1_REG));

    len = p - buf;

    return len;
}

static int tps_ioctl(struct inode *inode, struct file *filp,
			unsigned int cmd, unsigned long arg)
{
    int  ret = 0;

    DBGPRINT("%s: cmd: 0x%x, arg: %ld\n", __FUNCTION__, cmd, arg);

    switch(cmd)
    {
        case TPS_IOC_SLEEP:
            ret = tps_sleep(arg);
            break;

        case TPS_IOC_LED_ON:
            ret = tps_led_on(arg);
            break;

        case TPS_IOC_LED_OFF:
            ret = tps_led_off(arg);
            break;

        case TPS_IOC_LED_STATE:
            ret = tps_led_state(arg);
            break;

        case TPS_IOC_VIB_CMD:
            ret = tps_vib_cmd(arg);
            break;

        case TPS_IOC_VIB_STATE:
            ret = tps_vib_state();
            break;

        case TPS_IOC_QS6400_WAKE:
            ret = tps_qs6400_wake();
            break;

        default:
            printk("%s: bad ioctl cmd\n", __FUNCTION__);
            ret = -EINVAL;
            break;
    }

    return ret;
}

static int tps_open(struct inode *inode, struct file * filp)
{
    int  minor;

    DBGPRINT("%s\n", __FUNCTION__);

    minor = MINOR(inode->i_rdev); 
    if ( minor != TPS_MINOR )
    {
        return -ENODEV;
    }

#ifdef MODULE
    MOD_INC_USE_COUNT;
#endif

    return 0;
}

static int tps_release(struct inode *inode, struct file *filp)
{
    DBGPRINT("%s\n", __FUNCTION__);

#ifdef MODULE
    MOD_DEC_USE_COUNT;
#endif

    return 0;
}


static struct file_operations  tps_fops =
{
    owner:      THIS_MODULE,
    open:       tps_open,
    release:    tps_release,
    ioctl:      tps_ioctl,
};

static struct miscdevice  tps_miscdev =
{
    TPS_MINOR,
    "tps",
    &tps_fops
};


static int __init tps_init(void)
{
    int  ret;

    DBGPRINT("%s\n", __FUNCTION__);

    ret = i2c_add_driver(&tps_driver);
    if ( ret )
    {
        printk(KERN_INFO "failed to find TPS\n");
        return ret;
    }

    misc_register(&tps_miscdev);

    create_proc_read_entry(TPS_PROC_NAME, 0, NULL, tps_stats, NULL);

    return 0;
}

static void __exit tps_exit(void)
{
    DBGPRINT("%s\n", __FUNCTION__);

    remove_proc_entry(TPS_PROC_NAME, NULL);

    misc_deregister(&tps_miscdev);

    i2c_del_driver(&tps_driver);
}


module_init(tps_init);
module_exit(tps_exit);

EXPORT_SYMBOL(tps_set_lowpower);

EXPORT_SYMBOL(tps_sleep);

EXPORT_SYMBOL(tps_led_on);
EXPORT_SYMBOL(tps_led_off);
EXPORT_SYMBOL(tps_led_state);

EXPORT_SYMBOL(tps_vib_cmd);
EXPORT_SYMBOL(tps_vib_state);

EXPORT_SYMBOL(tps_qs6400_wake);

MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?