📄 pcf8574.c
字号:
/*
pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
Dan Eaton <dan.eaton@rocketlogix.com>
Ported to Linux 2.6 by Aurelien Jarno <aurel32@debian.org> with
the help of Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* A few notes about the PCF8574:
* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by
Philips Semiconductors. It is designed to provide a byte I2C
interface to up to 8 separate devices.
* The PCF8574 appears as a very simple SMBus device which can be
read from or written to with SMBUS byte read/write accesses.
--Dan
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2a,
I2C_CLIENT_END };
static struct i2c_client *g_client = NULL;
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
/* Initial values */
#define PCF8574_INIT 255 /* All outputs on (input mode) */
/* Each client has this additional data */
struct pcf8574_data {
struct i2c_client client;
u8 write; /* Remember last written value */
};
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind);
static int pcf8574_detach_client(struct i2c_client *client);
static void pcf8574_init_client(struct i2c_client *client);
/* This is the driver that will be inserted */
static struct i2c_driver pcf8574_driver = {
.driver = {
.name = "pcf8574",
},
.id = I2C_DRIVERID_PCF8574,
.attach_adapter = pcf8574_attach_adapter,
.detach_client = pcf8574_detach_client,
};
/* following are the sysfs callback functions */
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
return sprintf(buf, "%u\n", i2c_smbus_read_byte(client));
}
static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%u\n", data->write);
}
static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8574_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
if (val > 0xff)
return -EINVAL;
data->write = val;
i2c_smbus_write_byte(client, data->write);
return count;
}
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
/*
* Real code
*/
static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, pcf8574_detect);
}
#if 0
int pcf8574_read(u8 addr, u8 value)
{
int res=0;
char buf=value;
printk("%s\n",__FUNCTION__);
if( g_client == NULL )
return -1;
res = i2c_master_recv(g_client, &buf, 1);
if (res >0)
res =0;
else
res =-1;
printk(KERN_INFO "In funtion %s addr:%x value:%xreturn %d \n", __FUNCTION__, addr,value,res);
return res;
}
#endif
#if 1
int pcf8574_read(u8 addr, u8 *pvalue)
{
//printk("%s\n",__FUNCTION__);
int res=0;
char buf=0;
char buffer=0x0;
struct i2c_msg msgs[1] ={
// { addr, 0, 1, &buffer },
{ addr, 1, 1, &buf }};
printk("%s\n",__FUNCTION__);
if( g_client == NULL )
return -1;
// i2c_ov9640_inc_use(g_client);
// msgs[0].addr=msgs[1].addr=g_client->addr;
//msgs[0].addr=g_client->addr;
//res=i2c_transfer(g_client->adapter,&msgs[0],1);
//if (res<=0)
// goto out;
res=i2c_transfer(g_client->adapter,msgs,1);
if (res<=0)
goto out;
// printk("%s--buf value=%x\n",__FUNCTION__, buf);
*pvalue=buf;
printk("%s-- pvalue=%x\n",__FUNCTION__,*pvalue);
return buf;
// i2c_ov9640_dec_use(g_client);
out:
printk(KERN_INFO "In funtion %s addr:%x,value=%x\n", __FUNCTION__, addr,*pvalue);
if (res<=0) printk("res = %d \n",res);
return res;
}
#endif
int pcf8574_write(u8 addr, u8 value)
{
int res=0;
printk("%s\n",__FUNCTION__);
if( g_client == NULL )
return -1;
char buffer[1]={value};
struct i2c_msg msgs[1] =
{ addr, 0, 1, &buffer[0] };
res=i2c_transfer(g_client->adapter,msgs,1);
if (res<=0)
goto out;
//res = i2c_master_send(g_client, buf, 2);
//if (res >0)
// res =0;
//else
// res =-1;
printk(KERN_INFO "In funtion %s addr:%x value:%xreturn %d \n", __FUNCTION__, addr,value,res);
return res;
out:
printk(KERN_INFO "In funtion %s addr:%x,value=%x\n", __FUNCTION__, addr,value);
if (res<=0) printk("res = %d \n",res);
return res;
}
/* This function is called by i2c_probe */
static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct pcf8574_data *data;
int err = 0;
const char *client_name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
goto exit;
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet. */
if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &pcf8574_driver;
new_client->flags = 0;
g_client=new_client;
/* Now, we would do the remaining detection. But the PCF8574 is plainly
impossible to detect! Stupid chip. */
/* Determine the chip type */
if (kind <= 0) {
if (address >= 0x38 && address <= 0x3f)
kind = pcf8574a;
else
kind = pcf8574;
}
if (kind == pcf8574a)
client_name = "pcf8574a";
else
client_name = "pcf8574";
/* Fill in the remaining client fields and put it into the global list */
strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
{printk("pcf8574 cpld has been registered failed!\n");goto exit_free;}
else{printk("pcf8574 cpld has been registered success!\n");}
/* Initialize the PCF8574 chip */
pcf8574_init_client(new_client);
/* Register sysfs hooks */
device_create_file(&new_client->dev, &dev_attr_read);
device_create_file(&new_client->dev, &dev_attr_write);
return 0;
/* OK, this is not exactly good programming practice, usually. But it is
very code-efficient in this case. */
exit_free:
kfree(data);
exit:
return err;
}
static int pcf8574_detach_client(struct i2c_client *client)
{
int err;
if ((err = i2c_detach_client(client)))
return err;
kfree(i2c_get_clientdata(client));
return 0;
}
/* Called when we have found a new PCF8574. */
static void pcf8574_init_client(struct i2c_client *client)
{
struct pcf8574_data *data = i2c_get_clientdata(client);
data->write =0x0;// PCF8574_INIT;
i2c_smbus_write_byte(client, data->write);
}
static int __init pcf8574_init(void)
{
int res=0;
if ( (res = i2c_add_driver(&pcf8574_driver)) ) {
printk("pcf8574: Driver registration failed, module not inserted.\n");
i2c_del_driver(&pcf8574_driver);
return res;
}
if(g_client != NULL)
printk("I2C: driver for device %s registed!.\n", g_client->name);
else
printk("I2C: driver for device unregisted!.\n");
}
static void __exit pcf8574_exit(void)
{
i2c_del_driver(&pcf8574_driver);
}
MODULE_AUTHOR
("Frodo Looijaard <frodol@dds.nl>, "
"Philip Edelbrock <phil@netroedge.com>, "
"Dan Eaton <dan.eaton@rocketlogix.com> "
"and Aurelien Jarno <aurelien@aurel32.net>");
MODULE_DESCRIPTION("PCF8574 driver");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(pcf8574_write);
EXPORT_SYMBOL(pcf8574_read);
module_init(pcf8574_init);
module_exit(pcf8574_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -