400 lines
9.9 KiB
C
400 lines
9.9 KiB
C
|
|
/*
|
|||
|
|
* drivers/input/touchscreen/gslX680.c
|
|||
|
|
*
|
|||
|
|
* Copyright (c) 2012 Shanghai Basewin
|
|||
|
|
* Guan Yuwei<guanyuwei@basewin.com>
|
|||
|
|
*
|
|||
|
|
* This program is free software; you can redistribute it and/or modify
|
|||
|
|
* it under the terms of the GNU General Public License version 2 as
|
|||
|
|
* published by the Free Software Foundation.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
|
|||
|
|
#include <linux/module.h>
|
|||
|
|
#include <linux/delay.h>
|
|||
|
|
#include <linux/device.h>
|
|||
|
|
#include <linux/hrtimer.h>
|
|||
|
|
#include <linux/i2c.h>
|
|||
|
|
#include <linux/input.h>
|
|||
|
|
#include <linux/interrupt.h>
|
|||
|
|
#include <linux/io.h>
|
|||
|
|
#include <linux/platform_device.h>
|
|||
|
|
#include <linux/async.h>
|
|||
|
|
#include <linux/irq.h>
|
|||
|
|
#include <linux/workqueue.h>
|
|||
|
|
#include <linux/proc_fs.h>
|
|||
|
|
#include <linux/input/mt.h>
|
|||
|
|
|
|||
|
|
#include <linux/version.h>
|
|||
|
|
#include <linux/slab.h>
|
|||
|
|
#include <linux/of_gpio.h>
|
|||
|
|
#include <linux/wakelock.h>
|
|||
|
|
|
|||
|
|
#include <linux/iio/iio.h>
|
|||
|
|
#include <linux/iio/machine.h>
|
|||
|
|
#include <linux/iio/driver.h>
|
|||
|
|
#include <linux/iio/consumer.h>
|
|||
|
|
|
|||
|
|
#include <linux/blkdev.h>
|
|||
|
|
|
|||
|
|
#define PC9202_I2C_NAME "pc9202-wdt"
|
|||
|
|
#define SW2001_REG_DECRYPT_CTRL 0x00
|
|||
|
|
#define SW2001_REG_WDT_CTRL 0x01
|
|||
|
|
#define WDT_KICK_S_0_64 0xc8
|
|||
|
|
#define WDT_KICK_S_2_56 0xd8
|
|||
|
|
#define WDT_KICK_S_10_24 0xe8
|
|||
|
|
#define WDT_KICK_S_40_96 0xf8
|
|||
|
|
|
|||
|
|
static unsigned char demoBuffer[16];
|
|||
|
|
|
|||
|
|
struct sw2001 {
|
|||
|
|
struct i2c_client *client;
|
|||
|
|
struct mutex lock;
|
|||
|
|
//struct platform_device *sw2001_device;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static struct sw2001 *the_sw2001;
|
|||
|
|
static int major;
|
|||
|
|
static struct class *cls;
|
|||
|
|
static struct device *dev;
|
|||
|
|
int wd_en_gpio;
|
|||
|
|
|
|||
|
|
void enable_wdt(void)
|
|||
|
|
{
|
|||
|
|
if(wd_en_gpio >= 0)
|
|||
|
|
gpio_direction_output(wd_en_gpio, 1);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void disable_wdt(void)
|
|||
|
|
{
|
|||
|
|
if(wd_en_gpio >= 0)
|
|||
|
|
gpio_direction_output(wd_en_gpio, 0);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*-------------------------------------------------------------------------*/
|
|||
|
|
/* sw2001_write parameter:
|
|||
|
|
* reg:
|
|||
|
|
* data:
|
|||
|
|
*/
|
|||
|
|
int sw2001_write(unsigned char reg, unsigned char *buf, int len)
|
|||
|
|
{
|
|||
|
|
int status=0;
|
|||
|
|
|
|||
|
|
if (!the_sw2001)
|
|||
|
|
return -ENODEV;
|
|||
|
|
|
|||
|
|
mutex_lock(&the_sw2001->lock);
|
|||
|
|
|
|||
|
|
//status = i2c_smbus_write_byte_data(the_sw2001->client, reg, data);
|
|||
|
|
status = i2c_smbus_write_i2c_block_data(the_sw2001->client, reg, len, buf);
|
|||
|
|
|
|||
|
|
mutex_unlock(&the_sw2001->lock);
|
|||
|
|
|
|||
|
|
printk("%s: sw2001_write(0x%x,0x%x)\n", "pc9202", reg, *buf);
|
|||
|
|
|
|||
|
|
if(status)
|
|||
|
|
printk("error.. status=0x%x\n",status);
|
|||
|
|
|
|||
|
|
if(status>=len) return 0;
|
|||
|
|
else return status;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//********************************************************************************
|
|||
|
|
// function : iWriteByte(uint8_t addr, uint8_t data)
|
|||
|
|
// description : write data to byte addr(internal register address in device)
|
|||
|
|
// parameters :
|
|||
|
|
// addr : register address in device
|
|||
|
|
// data: data
|
|||
|
|
// return :
|
|||
|
|
// TRUE : success
|
|||
|
|
// FALSE : fail
|
|||
|
|
//*********************************************************************************
|
|||
|
|
bool iWriteByte(uint8_t addr, uint8_t data)
|
|||
|
|
{
|
|||
|
|
//sw2001_write(addr, &data, 1);
|
|||
|
|
return sw2001_write(addr, &data, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* sw2001_read parameter:
|
|||
|
|
* reg:
|
|||
|
|
* data:
|
|||
|
|
*/
|
|||
|
|
int sw2001_read(unsigned char reg, unsigned char *buf, int len)
|
|||
|
|
{
|
|||
|
|
int status=0;
|
|||
|
|
|
|||
|
|
if (!the_sw2001)
|
|||
|
|
return -ENODEV;
|
|||
|
|
mutex_lock(&the_sw2001->lock);
|
|||
|
|
//status = i2c_smbus_read_byte_data(the_sw2001->client, reg);
|
|||
|
|
status = i2c_smbus_read_i2c_block_data(the_sw2001->client, reg, len, buf);
|
|||
|
|
mutex_unlock(&the_sw2001->lock);
|
|||
|
|
printk("%s: sw2001_read(0x%x) return 0x%x\n", "pc9202", reg, status);
|
|||
|
|
|
|||
|
|
printk("status=0x%x\n",status);
|
|||
|
|
|
|||
|
|
if(status>=len) return 0;
|
|||
|
|
else return status;
|
|||
|
|
}
|
|||
|
|
EXPORT_SYMBOL(sw2001_read);
|
|||
|
|
|
|||
|
|
//*********************************************************************************
|
|||
|
|
// function : iReadByte(uint8_t addr, uint8_t data)
|
|||
|
|
// description : read data from addr(internal register address in device)
|
|||
|
|
// parameters :
|
|||
|
|
// addr : register address in device
|
|||
|
|
// data: data
|
|||
|
|
// return :
|
|||
|
|
// TRUE : success
|
|||
|
|
// FALSE : fail
|
|||
|
|
//*********************************************************************************
|
|||
|
|
bool iReadByte(uint8_t addr, uint8_t *data)
|
|||
|
|
{
|
|||
|
|
//sw2001_read(addr, data, 1);
|
|||
|
|
return sw2001_read(addr, data, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int pc9202_wdt_suspend(struct device *dev)
|
|||
|
|
{
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int pc9202_wdt_resume(struct device *dev)
|
|||
|
|
{
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int wdt_open(struct inode *inode, struct file *filp)
|
|||
|
|
{
|
|||
|
|
//printk("wdt_open \r\n");
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int wdt_release(struct inode *inode, struct file *filp)
|
|||
|
|
{
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
ssize_t wdt_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
|
|||
|
|
{
|
|||
|
|
#if 0
|
|||
|
|
uint8_t reg_value;
|
|||
|
|
iReadByte(SW2001_REG_WDT_CTRL, ®_value);
|
|||
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><DDB8>Ƶ<EFBFBD>Ӧ<EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD>ռ<EFBFBD> */
|
|||
|
|
if (copy_to_user(buf,®_value,1))
|
|||
|
|
{
|
|||
|
|
count=-EFAULT;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
//printk("wdt_read \r\n");
|
|||
|
|
return count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ssize_t wdt_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
|
|||
|
|
{
|
|||
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><DDB8>Ƶ<EFBFBD><C6B5>ں˿ռ<CBBF> */
|
|||
|
|
uint8_t len = (int)count;
|
|||
|
|
if(len>2)
|
|||
|
|
{
|
|||
|
|
printk("wdt:inviald value too long\r\n");
|
|||
|
|
return count;
|
|||
|
|
}
|
|||
|
|
if (copy_from_user(demoBuffer+*f_pos, buf, count))
|
|||
|
|
{
|
|||
|
|
count = -EFAULT;
|
|||
|
|
}
|
|||
|
|
switch(demoBuffer[0])
|
|||
|
|
{
|
|||
|
|
case '0':iWriteByte(SW2001_REG_WDT_CTRL,WDT_KICK_S_0_64);break;//0.64
|
|||
|
|
case '1':iWriteByte(SW2001_REG_WDT_CTRL,WDT_KICK_S_2_56);break;//2.56
|
|||
|
|
case '2':iWriteByte(SW2001_REG_WDT_CTRL,WDT_KICK_S_10_24);break;//10.24
|
|||
|
|
case '3':iWriteByte(SW2001_REG_WDT_CTRL,WDT_KICK_S_40_96);break;//40.96
|
|||
|
|
case 'e':enable_wdt();break; //enable wdt
|
|||
|
|
case 'd':disable_wdt();break; //disable wdt
|
|||
|
|
default:printk("wdt:inviald value \r\n");break;
|
|||
|
|
}
|
|||
|
|
//printk("wdt_weite %c\r\n", demoBuffer[0]);
|
|||
|
|
return count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
struct file_operations wdt_fops = {
|
|||
|
|
.owner = THIS_MODULE,
|
|||
|
|
.read = wdt_read,
|
|||
|
|
.write = wdt_write,
|
|||
|
|
.open = wdt_open,
|
|||
|
|
.release = wdt_release,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static int pc9202_wdt_probe(struct i2c_client *client,
|
|||
|
|
const struct i2c_device_id *id)
|
|||
|
|
{
|
|||
|
|
//struct device_node *np = client->dev.of_node;
|
|||
|
|
//struct sw2001 *ts;
|
|||
|
|
struct sw2001 *pEnc;
|
|||
|
|
uint8_t reg_value;
|
|||
|
|
struct iio_channel *channel;
|
|||
|
|
int raw;
|
|||
|
|
int retry_count, ret;
|
|||
|
|
|
|||
|
|
if (!of_device_is_available(client->dev.of_node)) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|||
|
|
dev_err(&client->dev, "I2C functionality not supported\n");
|
|||
|
|
return -ENODEV;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pEnc = kzalloc(sizeof(struct sw2001), GFP_KERNEL);
|
|||
|
|
if (!pEnc)
|
|||
|
|
return -ENOMEM;
|
|||
|
|
|
|||
|
|
mutex_init(&pEnc->lock);
|
|||
|
|
pEnc->client = client;
|
|||
|
|
i2c_set_clientdata(client,pEnc);
|
|||
|
|
the_sw2001 = pEnc;
|
|||
|
|
|
|||
|
|
for (retry_count = 0; retry_count < 100; retry_count++) {
|
|||
|
|
ret = iReadByte(SW2001_REG_WDT_CTRL, ®_value);
|
|||
|
|
if(0 != ret) {
|
|||
|
|
printk("====== i2c detect failed watchdog init err: 0x%x ======\n", reg_value);
|
|||
|
|
} else {
|
|||
|
|
printk("====== i2c detect success watchdog init ======\n");
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
msleep(10);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (0 != ret) {
|
|||
|
|
printk("====== i2c detect failed watchdog init ======\n");
|
|||
|
|
goto err;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
major = register_chrdev(0, "wdt_crl", &wdt_fops);
|
|||
|
|
if (major < 0)
|
|||
|
|
{
|
|||
|
|
printk("Unable to register wdt character device !\n");
|
|||
|
|
goto err;
|
|||
|
|
}
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
cls = class_create(THIS_MODULE, "wdt_crl");
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>豸<EFBFBD>ڵ<EFBFBD>
|
|||
|
|
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "wdt_crl");
|
|||
|
|
|
|||
|
|
if (of_find_property(client->dev.of_node, "firefly-server-r1", NULL)) {
|
|||
|
|
printk("%s(): SERVER-R1 watchdog enabled gpio init\n",__FUNCTION__);
|
|||
|
|
channel = iio_channel_get(&(client->dev), NULL);
|
|||
|
|
if (IS_ERR(channel)){
|
|||
|
|
channel = NULL;
|
|||
|
|
printk("%s() have not set adc chan\n", __FUNCTION__);
|
|||
|
|
goto err;
|
|||
|
|
}
|
|||
|
|
iio_read_channel_raw(channel, &raw);
|
|||
|
|
|
|||
|
|
if( (raw > 0 && raw < 20) || (raw > 540 && raw < 580) || (raw > 590 && raw < 630) ) {
|
|||
|
|
printk("%s(): SERVER-R1's main core board watchdog enabled gpio init\n",__FUNCTION__);
|
|||
|
|
wd_en_gpio = of_get_named_gpio_flags(client->dev.of_node, "wd-en-gpio-m", 0, NULL);
|
|||
|
|
} else {
|
|||
|
|
printk("%s(): SERVER-R1's sub core board watchdog enabled gpio init\n",__FUNCTION__);
|
|||
|
|
wd_en_gpio = of_get_named_gpio_flags(client->dev.of_node, "wd-en-gpio", 0, NULL);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!gpio_is_valid(wd_en_gpio)) {
|
|||
|
|
printk("%s(): wd_en_gpio: %d is invalid\n", __FUNCTION__, wd_en_gpio);
|
|||
|
|
goto err;
|
|||
|
|
}
|
|||
|
|
if (gpio_request(wd_en_gpio, "wdt-en")) {
|
|||
|
|
printk("%s(): gpio %d request failed!\n", __FUNCTION__, wd_en_gpio);
|
|||
|
|
gpio_free(wd_en_gpio);
|
|||
|
|
goto err;
|
|||
|
|
} else {
|
|||
|
|
gpio_direction_output(wd_en_gpio, 0);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
wd_en_gpio = of_get_named_gpio_flags(client->dev.of_node, "wd-en-gpio", 0, NULL);
|
|||
|
|
if (!gpio_is_valid(wd_en_gpio)) {
|
|||
|
|
printk("%s(): wd_en_gpio: %d is invalid\n", __FUNCTION__, wd_en_gpio);
|
|||
|
|
} else {
|
|||
|
|
if (gpio_request(wd_en_gpio, "wdt-en")) {
|
|||
|
|
printk("%s(): gpio %d request failed!\n", __FUNCTION__, wd_en_gpio);
|
|||
|
|
gpio_free(wd_en_gpio);
|
|||
|
|
goto err;
|
|||
|
|
} else {
|
|||
|
|
gpio_direction_output(wd_en_gpio, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
err:
|
|||
|
|
kfree(pEnc);
|
|||
|
|
i2c_set_clientdata(client, NULL);
|
|||
|
|
the_sw2001 = NULL;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int pc9202_wdt_remove(struct i2c_client *client)
|
|||
|
|
{
|
|||
|
|
struct sw2001 *axp = i2c_get_clientdata(client);
|
|||
|
|
|
|||
|
|
//PR_DEBUG("%s\n",__func__);
|
|||
|
|
|
|||
|
|
if(wd_en_gpio >= 0)
|
|||
|
|
gpio_free(wd_en_gpio);
|
|||
|
|
kfree(axp);
|
|||
|
|
i2c_set_clientdata(client, NULL);
|
|||
|
|
the_sw2001 = NULL;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static struct of_device_id pc9202_wdt_ids[] = {
|
|||
|
|
{.compatible = "firefly,pc9202"},
|
|||
|
|
{}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static const struct i2c_device_id pc9202_wdt_id[] = {
|
|||
|
|
{PC9202_I2C_NAME, 0},
|
|||
|
|
{}
|
|||
|
|
};
|
|||
|
|
MODULE_DEVICE_TABLE(i2c, pc9202_wdt_id);
|
|||
|
|
|
|||
|
|
static const struct dev_pm_ops pc9202_wdt_ops = {
|
|||
|
|
//.write = pc9202_wdt_write,
|
|||
|
|
.suspend = pc9202_wdt_suspend,
|
|||
|
|
.resume = pc9202_wdt_resume,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static struct i2c_driver pc9202_wdt_driver = {
|
|||
|
|
.driver = {
|
|||
|
|
.name = PC9202_I2C_NAME,
|
|||
|
|
.owner = THIS_MODULE,
|
|||
|
|
.of_match_table = of_match_ptr(pc9202_wdt_ids),
|
|||
|
|
.pm = &pc9202_wdt_ops,
|
|||
|
|
},
|
|||
|
|
.probe = pc9202_wdt_probe,
|
|||
|
|
.remove = pc9202_wdt_remove,
|
|||
|
|
.id_table = pc9202_wdt_id,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static int __init pc9202_wdt_init(void)
|
|||
|
|
{
|
|||
|
|
int ret;
|
|||
|
|
ret = i2c_add_driver(&pc9202_wdt_driver);
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
static void __exit pc9202_wdt_exit(void)
|
|||
|
|
{
|
|||
|
|
i2c_del_driver(&pc9202_wdt_driver);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
late_initcall(pc9202_wdt_init);
|
|||
|
|
module_exit(pc9202_wdt_exit);
|
|||
|
|
|
|||
|
|
MODULE_LICENSE("GPL");
|
|||
|
|
MODULE_DESCRIPTION("PC9202 watchdog driver");
|
|||
|
|
MODULE_AUTHOR("zjy, zhengjunye123@126.com");
|
|||
|
|
MODULE_ALIAS("platform:rk3399");
|