2026-01-21 18:59:54 +08:00

400 lines
9.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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, &reg_value);
/* <20><><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><DDB8>Ƶ<EFBFBD>Ӧ<EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD>ռ<EFBFBD> */
if (copy_to_user(buf,&reg_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, &reg_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");