400 lines
9.9 KiB
C
Raw Normal View History

2026-01-21 18:59:54 +08:00
/*
* 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");