Creation of Cybook 2416 (actually Gen4) repository

This commit is contained in:
mlt
2009-12-18 17:10:00 +00:00
committed by godzil
commit 76f20f4d40
13791 changed files with 6812321 additions and 0 deletions

134
drivers/i2c/chips/Kconfig Normal file
View File

@@ -0,0 +1,134 @@
#
# Miscellaneous I2C chip drivers configuration
#
menu "Miscellaneous I2C Chip support"
depends on I2C
config SENSORS_DS1337
tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
DS1337 and DS1339 real-time clock chips.
This driver can also be built as a module. If so, the module
will be called ds1337.
config SENSORS_DS1374
tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
DS1374 real-time clock chips.
This driver can also be built as a module. If so, the module
will be called ds1374.
config SENSORS_EEPROM
tristate "EEPROM reader"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get read-only access to the EEPROM data
available on modern memory DIMMs and Sony Vaio laptops. Such
EEPROMs could theoretically be available on other devices as well.
This driver can also be built as a module. If so, the module
will be called eeprom.
config SENSORS_PCF8574
tristate "Philips PCF8574 and PCF8574A"
depends on I2C && EXPERIMENTAL
default n
help
If you say yes here you get support for Philips PCF8574 and
PCF8574A chips.
This driver can also be built as a module. If so, the module
will be called pcf8574.
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
config SENSORS_PCA9539
tristate "Philips PCA9539 16-bit I/O port"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Philips PCA9539
16-bit I/O port.
This driver can also be built as a module. If so, the module
will be called pca9539.
config SENSORS_PCF8591
tristate "Philips PCF8591"
depends on I2C && EXPERIMENTAL
default n
help
If you say yes here you get support for Philips PCF8591 chips.
This driver can also be built as a module. If so, the module
will be called pcf8591.
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
help
If you say yes here you get support for the Philips ISP1301
USB-On-The-Go transceiver working with the OMAP OTG controller.
The ISP1301 is used in products including H2 and H3 development
boards for Texas Instruments OMAP processors.
This driver can also be built as a module. If so, the module
will be called isp1301_omap.
# NOTE: This isn't really OMAP-specific, except for the current
# interface location in <include/asm-arm/arch-omap/tps65010.h>
# and having mostly OMAP-specific board support
config TPS65010
tristate "TPS6501x Power Management chips"
depends on I2C && ARCH_OMAP
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes here you get support for the TPS6501x series of
Power Management chips. These include voltage regulators,
lithium ion/polymer battery charging, and other features that
are often used in portable devices like cell phones and cameras.
This driver can also be built as a module. If so, the module
will be called tps65010.
config SENSORS_M41T00
tristate "ST M41T00 RTC chip"
depends on I2C && PPC32
help
If you say yes here you get support for the ST M41T00 RTC chip.
This driver can also be built as a module. If so, the module
will be called m41t00.
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Maxim MAX6875
EEPROM-programmable, quad power-supply sequencer/supervisor.
This provides an interface to program the EEPROM and reset the chip.
This driver also supports the Maxim MAX6874 hex power-supply
sequencer/supervisor if found at a compatible address.
This driver can also be built as a module. If so, the module
will be called max6875.
#Qisda Tony 090406, add Auo touch i2c driver [
config QISDA_IIC
tristate "New IIC interface for Qidsa use"
default n
help
tony.yc.huang@qisda.com
#Qisda Tony 090406, add Auo touch i2c driver ]
endmenu

View File

@@ -0,0 +1,21 @@
#
# Makefile for miscellaneous I2C chip drivers.
#
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
#Qisda Tony 090406, add Auo touch i2c driver [
obj-$(CONFIG_QISDA_IIC) += qisda_iic.o
#Qisda Tony 090406, add Auo touch i2c driver ]
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
endif

410
drivers/i2c/chips/ds1337.c Normal file
View File

@@ -0,0 +1,410 @@
/*
* linux/drivers/i2c/chips/ds1337.c
*
* Copyright (C) 2005 James Chapman <jchapman@katalix.com>
*
* based on linux/drivers/acorn/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
* 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.
*
* Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/bcd.h>
#include <linux/list.h>
/* Device registers */
#define DS1337_REG_HOUR 2
#define DS1337_REG_DAY 3
#define DS1337_REG_DATE 4
#define DS1337_REG_MONTH 5
#define DS1337_REG_CONTROL 14
#define DS1337_REG_STATUS 15
/* FIXME - how do we export these interface constants? */
#define DS1337_GET_DATE 0
#define DS1337_SET_DATE 1
/*
* Functions declaration
*/
static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(ds1337);
static int ds1337_attach_adapter(struct i2c_adapter *adapter);
static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
static void ds1337_init_client(struct i2c_client *client);
static int ds1337_detach_client(struct i2c_client *client);
static int ds1337_command(struct i2c_client *client, unsigned int cmd,
void *arg);
/*
* Driver data (common to all clients)
*/
static struct i2c_driver ds1337_driver = {
.driver = {
.name = "ds1337",
},
.attach_adapter = ds1337_attach_adapter,
.detach_client = ds1337_detach_client,
.command = ds1337_command,
};
/*
* Client data (each client gets its own)
*/
struct ds1337_data {
struct i2c_client client;
struct list_head list;
};
/*
* Internal variables
*/
static LIST_HEAD(ds1337_clients);
static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
{
s32 tmp = i2c_smbus_read_byte_data(client, reg);
if (tmp < 0)
return -EIO;
*value = tmp;
return 0;
}
/*
* Chip access functions
*/
static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
{
int result;
u8 buf[7];
u8 val;
struct i2c_msg msg[2];
u8 offs = 0;
if (!dt) {
dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
return -EINVAL;
}
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &offs;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = sizeof(buf);
msg[1].buf = &buf[0];
result = i2c_transfer(client->adapter, msg, 2);
dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6]);
if (result == 2) {
dt->tm_sec = BCD2BIN(buf[0]);
dt->tm_min = BCD2BIN(buf[1]);
val = buf[2] & 0x3f;
dt->tm_hour = BCD2BIN(val);
dt->tm_wday = BCD2BIN(buf[3]) - 1;
dt->tm_mday = BCD2BIN(buf[4]);
val = buf[5] & 0x7f;
dt->tm_mon = BCD2BIN(val) - 1;
dt->tm_year = BCD2BIN(buf[6]);
if (buf[5] & 0x80)
dt->tm_year += 100;
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__, dt->tm_sec, dt->tm_min,
dt->tm_hour, dt->tm_mday,
dt->tm_mon, dt->tm_year, dt->tm_wday);
return 0;
}
dev_err(&client->dev, "error reading data! %d\n", result);
return -EIO;
}
static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
{
int result;
u8 buf[8];
u8 val;
struct i2c_msg msg[1];
if (!dt) {
dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
return -EINVAL;
}
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
dt->tm_sec, dt->tm_min, dt->tm_hour,
dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
buf[0] = 0; /* reg offset */
buf[1] = BIN2BCD(dt->tm_sec);
buf[2] = BIN2BCD(dt->tm_min);
buf[3] = BIN2BCD(dt->tm_hour);
buf[4] = BIN2BCD(dt->tm_wday + 1);
buf[5] = BIN2BCD(dt->tm_mday);
buf[6] = BIN2BCD(dt->tm_mon + 1);
val = dt->tm_year;
if (val >= 100) {
val -= 100;
buf[6] |= (1 << 7);
}
buf[7] = BIN2BCD(val);
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = sizeof(buf);
msg[0].buf = &buf[0];
result = i2c_transfer(client->adapter, msg, 1);
if (result == 1)
return 0;
dev_err(&client->dev, "error writing data! %d\n", result);
return -EIO;
}
static int ds1337_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
switch (cmd) {
case DS1337_GET_DATE:
return ds1337_get_datetime(client, arg);
case DS1337_SET_DATE:
return ds1337_set_datetime(client, arg);
default:
return -EINVAL;
}
}
/*
* Public API for access to specific device. Useful for low-level
* RTC access from kernel code.
*/
int ds1337_do_command(int bus, int cmd, void *arg)
{
struct list_head *walk;
struct list_head *tmp;
struct ds1337_data *data;
list_for_each_safe(walk, tmp, &ds1337_clients) {
data = list_entry(walk, struct ds1337_data, list);
if (data->client.adapter->nr == bus)
return ds1337_command(&data->client, cmd, arg);
}
return -ENODEV;
}
static int ds1337_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, ds1337_detect);
}
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
*/
static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct ds1337_data *data;
int err = 0;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_I2C))
goto exit;
if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
INIT_LIST_HEAD(&data->list);
/* The common I2C client data is placed right before the
* DS1337-specific data.
*/
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &ds1337_driver;
new_client->flags = 0;
/*
* Now we do the remaining detection. A negative kind means that
* the driver was loaded with no force parameter (default), so we
* must both detect and identify the chip. A zero kind means that
* the driver was loaded with the force parameter, the detection
* step shall be skipped. A positive kind means that the driver
* was loaded with the force parameter and a given kind of chip is
* requested, so both the detection and the identification steps
* are skipped.
*
* For detection, we read registers that are most likely to cause
* detection failure, i.e. those that have more bits with fixed
* or reserved values.
*/
/* Default to an DS1337 if forced */
if (kind == 0)
kind = ds1337;
if (kind < 0) { /* detection and identification */
u8 data;
/* Check that status register bits 6-2 are zero */
if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
(data & 0x7c))
goto exit_free;
/* Check for a valid day register value */
if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
(data == 0) || (data & 0xf8))
goto exit_free;
/* Check for a valid date register value */
if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
(data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
(data >= 0x32))
goto exit_free;
/* Check for a valid month register value */
if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
(data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
((data >= 0x13) && (data <= 0x19)))
goto exit_free;
/* Check that control register bits 6-5 are zero */
if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
(data & 0x60))
goto exit_free;
kind = ds1337;
}
if (kind == ds1337)
name = "ds1337";
/* We can fill in the remaining client fields */
strlcpy(new_client->name, name, I2C_NAME_SIZE);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the DS1337 chip */
ds1337_init_client(new_client);
/* Add client to local list */
list_add(&data->list, &ds1337_clients);
return 0;
exit_free:
kfree(data);
exit:
return err;
}
static void ds1337_init_client(struct i2c_client *client)
{
u8 status, control;
/* On some boards, the RTC isn't configured by boot firmware.
* Handle that case by starting/configuring the RTC now.
*/
status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
if ((status & 0x80) || (control & 0x80)) {
/* RTC not running */
u8 buf[1+16]; /* First byte is interpreted as address */
struct i2c_msg msg[1];
dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);
/* Initialize all, including STATUS and CONTROL to zero */
memset(buf, 0, sizeof(buf));
/* Write valid values in the date/time registers */
buf[1+DS1337_REG_DAY] = 1;
buf[1+DS1337_REG_DATE] = 1;
buf[1+DS1337_REG_MONTH] = 1;
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = sizeof(buf);
msg[0].buf = &buf[0];
i2c_transfer(client->adapter, msg, 1);
} else {
/* Running: ensure that device is set in 24-hour mode */
s32 val;
val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
if ((val >= 0) && (val & (1 << 6)))
i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
val & 0x3f);
}
}
static int ds1337_detach_client(struct i2c_client *client)
{
int err;
struct ds1337_data *data = i2c_get_clientdata(client);
if ((err = i2c_detach_client(client)))
return err;
list_del(&data->list);
kfree(data);
return 0;
}
static int __init ds1337_init(void)
{
return i2c_add_driver(&ds1337_driver);
}
static void __exit ds1337_exit(void)
{
i2c_del_driver(&ds1337_driver);
}
MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
MODULE_DESCRIPTION("DS1337 RTC driver");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL_GPL(ds1337_do_command);
module_init(ds1337_init);
module_exit(ds1337_exit);

267
drivers/i2c/chips/ds1374.c Normal file
View File

@@ -0,0 +1,267 @@
/*
* drivers/i2c/chips/ds1374.c
*
* I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
*
* Author: Randy Vinson <rvinson@mvista.com>
*
* Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
*
* 2005 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
/*
* This i2c client/driver wedges between the drivers/char/genrtc.c RTC
* interface and the SMBus interface of the i2c subsystem.
* It would be more efficient to use i2c msgs/i2c_transfer directly but, as
* recommened in .../Documentation/i2c/writing-clients section
* "Sending and receiving", using SMBus level communication is preferred.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#define DS1374_REG_TOD0 0x00
#define DS1374_REG_TOD1 0x01
#define DS1374_REG_TOD2 0x02
#define DS1374_REG_TOD3 0x03
#define DS1374_REG_WDALM0 0x04
#define DS1374_REG_WDALM1 0x05
#define DS1374_REG_WDALM2 0x06
#define DS1374_REG_CR 0x07
#define DS1374_REG_SR 0x08
#define DS1374_REG_SR_OSF 0x80
#define DS1374_REG_TCR 0x09
#define DS1374_DRV_NAME "ds1374"
static DEFINE_MUTEX(ds1374_mutex);
static struct i2c_driver ds1374_driver;
static struct i2c_client *save_client;
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
};
static ulong ds1374_read_rtc(void)
{
ulong time = 0;
int reg = DS1374_REG_WDALM0;
while (reg--) {
s32 tmp;
if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
dev_warn(&save_client->dev,
"can't read from rtc chip\n");
return 0;
}
time = (time << 8) | (tmp & 0xff);
}
return time;
}
static void ds1374_write_rtc(ulong time)
{
int reg;
for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
< 0) {
dev_warn(&save_client->dev,
"can't write to rtc chip\n");
break;
}
time = time >> 8;
}
}
static void ds1374_check_rtc_status(void)
{
s32 tmp;
tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
if (tmp < 0) {
dev_warn(&save_client->dev,
"can't read status from rtc chip\n");
return;
}
if (tmp & DS1374_REG_SR_OSF) {
dev_warn(&save_client->dev,
"oscillator discontinuity flagged, time unreliable\n");
tmp &= ~DS1374_REG_SR_OSF;
tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
tmp & 0xff);
if (tmp < 0)
dev_warn(&save_client->dev,
"can't clear discontinuity notification\n");
}
}
ulong ds1374_get_rtc_time(void)
{
ulong t1, t2;
int limit = 10; /* arbitrary retry limit */
mutex_lock(&ds1374_mutex);
/*
* Since the reads are being performed one byte at a time using
* the SMBus vs a 4-byte i2c transfer, there is a chance that a
* carry will occur during the read. To detect this, 2 reads are
* performed and compared.
*/
do {
t1 = ds1374_read_rtc();
t2 = ds1374_read_rtc();
} while (t1 != t2 && limit--);
mutex_unlock(&ds1374_mutex);
if (t1 != t2) {
dev_warn(&save_client->dev,
"can't get consistent time from rtc chip\n");
t1 = 0;
}
return t1;
}
static ulong new_time;
static void ds1374_set_work(struct work_struct *work)
{
ulong t1, t2;
int limit = 10; /* arbitrary retry limit */
t1 = new_time;
mutex_lock(&ds1374_mutex);
/*
* Since the writes are being performed one byte at a time using
* the SMBus vs a 4-byte i2c transfer, there is a chance that a
* carry will occur during the write. To detect this, the write
* value is read back and compared.
*/
do {
ds1374_write_rtc(t1);
t2 = ds1374_read_rtc();
} while (t1 != t2 && limit--);
mutex_unlock(&ds1374_mutex);
if (t1 != t2)
dev_warn(&save_client->dev,
"can't confirm time set from rtc chip\n");
}
static struct workqueue_struct *ds1374_workqueue;
static DECLARE_WORK(ds1374_work, ds1374_set_work);
int ds1374_set_rtc_time(ulong nowtime)
{
new_time = nowtime;
if (in_interrupt())
queue_work(ds1374_workqueue, &ds1374_work);
else
ds1374_set_work(NULL);
return 0;
}
/*
*****************************************************************************
*
* Driver Interface
*
*****************************************************************************
*/
static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *client;
int rc;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!client)
return -ENOMEM;
strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
client->addr = addr;
client->adapter = adap;
client->driver = &ds1374_driver;
ds1374_workqueue = create_singlethread_workqueue("ds1374");
if (!ds1374_workqueue) {
kfree(client);
return -ENOMEM; /* most expected reason */
}
if ((rc = i2c_attach_client(client)) != 0) {
kfree(client);
return rc;
}
save_client = client;
ds1374_check_rtc_status();
return 0;
}
static int ds1374_attach(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, ds1374_probe);
}
static int ds1374_detach(struct i2c_client *client)
{
int rc;
if ((rc = i2c_detach_client(client)) == 0) {
kfree(i2c_get_clientdata(client));
destroy_workqueue(ds1374_workqueue);
}
return rc;
}
static struct i2c_driver ds1374_driver = {
.driver = {
.name = DS1374_DRV_NAME,
},
.id = I2C_DRIVERID_DS1374,
.attach_adapter = ds1374_attach,
.detach_client = ds1374_detach,
};
static int __init ds1374_init(void)
{
return i2c_add_driver(&ds1374_driver);
}
static void __exit ds1374_exit(void)
{
i2c_del_driver(&ds1374_driver);
}
module_init(ds1374_init);
module_exit(ds1374_exit);
MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
MODULE_LICENSE("GPL");

258
drivers/i2c/chips/eeprom.c Normal file
View File

@@ -0,0 +1,258 @@
/*
eeprom.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com>
Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
Copyright (C) 2003 IBM Corp.
2004-01-16 Jean Delvare <khali@linux-fr.org>
Divide the eeprom in 32-byte (arbitrary) slices. This significantly
speeds sensors up, as well as various scripts using the eeprom
module.
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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(eeprom);
/* Size of EEPROM in bytes */
#define EEPROM_SIZE 256
/* possible types of eeprom devices */
enum eeprom_nature {
UNKNOWN,
VAIO,
};
/* Each client has this additional data */
struct eeprom_data {
struct i2c_client client;
struct mutex update_lock;
u8 valid; /* bitfield, bit!=0 if slice is valid */
unsigned long last_updated[8]; /* In jiffies, 8 slices */
u8 data[EEPROM_SIZE]; /* Register values */
enum eeprom_nature nature;
};
static int eeprom_attach_adapter(struct i2c_adapter *adapter);
static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind);
static int eeprom_detach_client(struct i2c_client *client);
/* This is the driver that will be inserted */
static struct i2c_driver eeprom_driver = {
.driver = {
.name = "eeprom",
},
.id = I2C_DRIVERID_EEPROM,
.attach_adapter = eeprom_attach_adapter,
.detach_client = eeprom_detach_client,
};
static void eeprom_update_client(struct i2c_client *client, u8 slice)
{
struct eeprom_data *data = i2c_get_clientdata(client);
int i, j;
mutex_lock(&data->update_lock);
if (!(data->valid & (1 << slice)) ||
time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX)
if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX)
goto exit;
} else {
if (i2c_smbus_write_byte(client, slice << 5)) {
dev_dbg(&client->dev, "eeprom read start has failed!\n");
goto exit;
}
for (i = slice << 5; i < (slice + 1) << 5; i++) {
j = i2c_smbus_read_byte(client);
if (j < 0)
goto exit;
data->data[i] = (u8) j;
}
}
data->last_updated[slice] = jiffies;
data->valid |= (1 << slice);
}
exit:
mutex_unlock(&data->update_lock);
}
static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
struct eeprom_data *data = i2c_get_clientdata(client);
u8 slice;
if (off > EEPROM_SIZE)
return 0;
if (off + count > EEPROM_SIZE)
count = EEPROM_SIZE - off;
/* Only refresh slices which contain requested bytes */
for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
eeprom_update_client(client, slice);
/* Hide Vaio security settings to regular users (16 first bytes) */
if (data->nature == VAIO && off < 16 && !capable(CAP_SYS_ADMIN)) {
size_t in_row1 = 16 - off;
in_row1 = min(in_row1, count);
memset(buf, 0, in_row1);
if (count - in_row1 > 0)
memcpy(buf + in_row1, &data->data[16], count - in_row1);
} else {
memcpy(buf, &data->data[off], count);
}
return count;
}
static struct bin_attribute eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
.owner = THIS_MODULE,
},
.size = EEPROM_SIZE,
.read = eeprom_read,
};
static int eeprom_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, eeprom_detect);
}
/* This function is called by i2c_probe */
static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct eeprom_data *data;
int err = 0;
/* There are three ways we can read the EEPROM data:
(1) I2C block reads (faster, but unsupported by most adapters)
(2) Consecutive byte reads (100% overhead)
(3) Regular byte data reads (200% overhead)
The third method is not implemented by this driver because all
known adapters support at least the second. */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA
| I2C_FUNC_SMBUS_BYTE))
goto exit;
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
new_client = &data->client;
memset(data->data, 0xff, EEPROM_SIZE);
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &eeprom_driver;
new_client->flags = 0;
/* Fill in the remaining client fields */
strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE);
data->valid = 0;
mutex_init(&data->update_lock);
data->nature = UNKNOWN;
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_kfree;
/* Detect the Vaio nature of EEPROMs.
We use the "PCG-" prefix as the signature. */
if (address == 0x57) {
if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
&& i2c_smbus_read_byte(new_client) == 'C'
&& i2c_smbus_read_byte(new_client) == 'G'
&& i2c_smbus_read_byte(new_client) == '-') {
dev_info(&new_client->dev, "Vaio EEPROM detected, "
"enabling password protection\n");
data->nature = VAIO;
}
}
/* create the sysfs eeprom file */
err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
if (err)
goto exit_detach;
return 0;
exit_detach:
i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
return err;
}
static int eeprom_detach_client(struct i2c_client *client)
{
int err;
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
err = i2c_detach_client(client);
if (err)
return err;
kfree(i2c_get_clientdata(client));
return 0;
}
static int __init eeprom_init(void)
{
return i2c_add_driver(&eeprom_driver);
}
static void __exit eeprom_exit(void)
{
i2c_del_driver(&eeprom_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
"Philip Edelbrock <phil@netroedge.com> and "
"Greg Kroah-Hartman <greg@kroah.com>");
MODULE_DESCRIPTION("I2C EEPROM driver");
MODULE_LICENSE("GPL");
module_init(eeprom_init);
module_exit(eeprom_exit);

File diff suppressed because it is too large Load Diff

413
drivers/i2c/chips/m41t00.c Normal file
View File

@@ -0,0 +1,413 @@
/*
* I2C client/driver for the ST M41T00 family of i2c rtc chips.
*
* Author: Mark A. Greer <mgreer@mvista.com>
*
* 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
/*
* This i2c client/driver wedges between the drivers/char/genrtc.c RTC
* interface and the SMBus interface of the i2c subsystem.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/m41t00.h>
#include <asm/time.h>
#include <asm/rtc.h>
static struct i2c_driver m41t00_driver;
static struct i2c_client *save_client;
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
};
struct m41t00_chip_info {
u8 type;
char *name;
u8 read_limit;
u8 sec; /* Offsets for chip regs */
u8 min;
u8 hour;
u8 day;
u8 mon;
u8 year;
u8 alarm_mon;
u8 alarm_hour;
u8 sqw;
u8 sqw_freq;
};
static struct m41t00_chip_info m41t00_chip_info_tbl[] = {
{
.type = M41T00_TYPE_M41T00,
.name = "m41t00",
.read_limit = 5,
.sec = 0,
.min = 1,
.hour = 2,
.day = 4,
.mon = 5,
.year = 6,
},
{
.type = M41T00_TYPE_M41T81,
.name = "m41t81",
.read_limit = 1,
.sec = 1,
.min = 2,
.hour = 3,
.day = 5,
.mon = 6,
.year = 7,
.alarm_mon = 0xa,
.alarm_hour = 0xc,
.sqw = 0x13,
},
{
.type = M41T00_TYPE_M41T85,
.name = "m41t85",
.read_limit = 1,
.sec = 1,
.min = 2,
.hour = 3,
.day = 5,
.mon = 6,
.year = 7,
.alarm_mon = 0xa,
.alarm_hour = 0xc,
.sqw = 0x13,
},
};
static struct m41t00_chip_info *m41t00_chip;
ulong
m41t00_get_rtc_time(void)
{
s32 sec, min, hour, day, mon, year;
s32 sec1, min1, hour1, day1, mon1, year1;
u8 reads = 0;
u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
struct i2c_msg msgs[] = {
{
.addr = save_client->addr,
.flags = 0,
.len = 1,
.buf = msgbuf,
},
{
.addr = save_client->addr,
.flags = I2C_M_RD,
.len = 8,
.buf = buf,
},
};
sec = min = hour = day = mon = year = 0;
do {
if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
goto read_err;
sec1 = sec;
min1 = min;
hour1 = hour;
day1 = day;
mon1 = mon;
year1 = year;
sec = buf[m41t00_chip->sec] & 0x7f;
min = buf[m41t00_chip->min] & 0x7f;
hour = buf[m41t00_chip->hour] & 0x3f;
day = buf[m41t00_chip->day] & 0x3f;
mon = buf[m41t00_chip->mon] & 0x1f;
year = buf[m41t00_chip->year];
} while ((++reads < m41t00_chip->read_limit) && ((sec != sec1)
|| (min != min1) || (hour != hour1) || (day != day1)
|| (mon != mon1) || (year != year1)));
if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1)
|| (hour != hour1) || (day != day1) || (mon != mon1)
|| (year != year1)))
goto read_err;
sec = BCD2BIN(sec);
min = BCD2BIN(min);
hour = BCD2BIN(hour);
day = BCD2BIN(day);
mon = BCD2BIN(mon);
year = BCD2BIN(year);
year += 1900;
if (year < 1970)
year += 100;
return mktime(year, mon, day, hour, min, sec);
read_err:
dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
return 0;
}
EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
static void
m41t00_set(void *arg)
{
struct rtc_time tm;
int nowtime = *(int *)arg;
s32 sec, min, hour, day, mon, year;
u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
struct i2c_msg msgs[] = {
{
.addr = save_client->addr,
.flags = 0,
.len = 1,
.buf = msgbuf,
},
{
.addr = save_client->addr,
.flags = I2C_M_RD,
.len = 8,
.buf = buf,
},
};
to_tm(nowtime, &tm);
tm.tm_year = (tm.tm_year - 1900) % 100;
sec = BIN2BCD(tm.tm_sec);
min = BIN2BCD(tm.tm_min);
hour = BIN2BCD(tm.tm_hour);
day = BIN2BCD(tm.tm_mday);
mon = BIN2BCD(tm.tm_mon);
year = BIN2BCD(tm.tm_year);
/* Read reg values into buf[0..7]/wbuf[1..8] */
if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
dev_err(&save_client->dev, "m41t00_set: Read error\n");
return;
}
wbuf[0] = 0; /* offset into rtc's regs */
buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f);
buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f);
buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
buf[m41t00_chip->year] = year;
if (i2c_master_send(save_client, wbuf, 9) < 0)
dev_err(&save_client->dev, "m41t00_set: Write error\n");
}
static ulong new_time;
/* well, isn't this API just _lovely_? */
static void
m41t00_barf(struct work_struct *unusable)
{
m41t00_set(&new_time);
}
static struct workqueue_struct *m41t00_wq;
static DECLARE_WORK(m41t00_work, m41t00_barf);
int
m41t00_set_rtc_time(ulong nowtime)
{
new_time = nowtime;
if (in_interrupt())
queue_work(m41t00_wq, &m41t00_work);
else
m41t00_set(&new_time);
return 0;
}
EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
/*
*****************************************************************************
*
* platform_data Driver Interface
*
*****************************************************************************
*/
static int __init
m41t00_platform_probe(struct platform_device *pdev)
{
struct m41t00_platform_data *pdata;
int i;
if (pdev && (pdata = pdev->dev.platform_data)) {
normal_addr[0] = pdata->i2c_addr;
for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++)
if (m41t00_chip_info_tbl[i].type == pdata->type) {
m41t00_chip = &m41t00_chip_info_tbl[i];
m41t00_chip->sqw_freq = pdata->sqw_freq;
return 0;
}
}
return -ENODEV;
}
static int __exit
m41t00_platform_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver m41t00_platform_driver = {
.probe = m41t00_platform_probe,
.remove = m41t00_platform_remove,
.driver = {
.owner = THIS_MODULE,
.name = M41T00_DRV_NAME,
},
};
/*
*****************************************************************************
*
* Driver Interface
*
*****************************************************************************
*/
static int
m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *client;
int rc;
if (!i2c_check_functionality(adap, I2C_FUNC_I2C
| I2C_FUNC_SMBUS_BYTE_DATA))
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!client)
return -ENOMEM;
strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE);
client->addr = addr;
client->adapter = adap;
client->driver = &m41t00_driver;
if ((rc = i2c_attach_client(client)))
goto attach_err;
if (m41t00_chip->type != M41T00_TYPE_M41T00) {
/* If asked, disable SQW, set SQW frequency & re-enable */
if (m41t00_chip->sqw_freq)
if (((rc = i2c_smbus_read_byte_data(client,
m41t00_chip->alarm_mon)) < 0)
|| ((rc = i2c_smbus_write_byte_data(client,
m41t00_chip->alarm_mon, rc & ~0x40)) <0)
|| ((rc = i2c_smbus_write_byte_data(client,
m41t00_chip->sqw,
m41t00_chip->sqw_freq)) < 0)
|| ((rc = i2c_smbus_write_byte_data(client,
m41t00_chip->alarm_mon, rc | 0x40)) <0))
goto sqw_err;
/* Make sure HT (Halt Update) bit is cleared */
if ((rc = i2c_smbus_read_byte_data(client,
m41t00_chip->alarm_hour)) < 0)
goto ht_err;
if (rc & 0x40)
if ((rc = i2c_smbus_write_byte_data(client,
m41t00_chip->alarm_hour, rc & ~0x40))<0)
goto ht_err;
}
/* Make sure ST (stop) bit is cleared */
if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0)
goto st_err;
if (rc & 0x80)
if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec,
rc & ~0x80)) < 0)
goto st_err;
m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
save_client = client;
return 0;
st_err:
dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n");
goto attach_err;
ht_err:
dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n");
goto attach_err;
sqw_err:
dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n");
attach_err:
kfree(client);
return rc;
}
static int
m41t00_attach(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, m41t00_probe);
}
static int
m41t00_detach(struct i2c_client *client)
{
int rc;
if ((rc = i2c_detach_client(client)) == 0) {
kfree(client);
destroy_workqueue(m41t00_wq);
}
return rc;
}
static struct i2c_driver m41t00_driver = {
.driver = {
.name = M41T00_DRV_NAME,
},
.id = I2C_DRIVERID_STM41T00,
.attach_adapter = m41t00_attach,
.detach_client = m41t00_detach,
};
static int __init
m41t00_init(void)
{
int rc;
if (!(rc = platform_driver_register(&m41t00_platform_driver)))
rc = i2c_add_driver(&m41t00_driver);
return rc;
}
static void __exit
m41t00_exit(void)
{
i2c_del_driver(&m41t00_driver);
platform_driver_unregister(&m41t00_platform_driver);
}
module_init(m41t00_init);
module_exit(m41t00_exit);
MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
MODULE_LICENSE("GPL");

272
drivers/i2c/chips/max6875.c Normal file
View File

@@ -0,0 +1,272 @@
/*
max6875.c - driver for MAX6874/MAX6875
Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
Based on i2c/chips/eeprom.c
The MAX6875 has a bank of registers and two banks of EEPROM.
Address ranges are defined as follows:
* 0x0000 - 0x0046 = configuration registers
* 0x8000 - 0x8046 = configuration EEPROM
* 0x8100 - 0x82FF = user EEPROM
This driver makes the user EEPROM available for read.
The registers & config EEPROM should be accessed via i2c-dev.
The MAX6875 ignores the lowest address bit, so each chip responds to
two addresses - 0x50/0x51 and 0x52/0x53.
Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read
address, so this driver is destructive if loaded for the wrong EEPROM chip.
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; version 2 of the License.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
static unsigned short normal_i2c[] = {I2C_CLIENT_END};
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(max6875);
/* The MAX6875 can only read/write 16 bytes at a time */
#define SLICE_SIZE 16
#define SLICE_BITS 4
/* USER EEPROM is at addresses 0x8100 - 0x82FF */
#define USER_EEPROM_BASE 0x8100
#define USER_EEPROM_SIZE 0x0200
#define USER_EEPROM_SLICES 32
/* MAX6875 commands */
#define MAX6875_CMD_BLK_READ 0x84
/* Each client has this additional data */
struct max6875_data {
struct i2c_client client;
struct mutex update_lock;
u32 valid;
u8 data[USER_EEPROM_SIZE];
unsigned long last_updated[USER_EEPROM_SLICES];
};
static int max6875_attach_adapter(struct i2c_adapter *adapter);
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind);
static int max6875_detach_client(struct i2c_client *client);
/* This is the driver that will be inserted */
static struct i2c_driver max6875_driver = {
.driver = {
.name = "max6875",
},
.attach_adapter = max6875_attach_adapter,
.detach_client = max6875_detach_client,
};
static void max6875_update_slice(struct i2c_client *client, int slice)
{
struct max6875_data *data = i2c_get_clientdata(client);
int i, j, addr;
u8 *buf;
if (slice >= USER_EEPROM_SLICES)
return;
mutex_lock(&data->update_lock);
buf = &data->data[slice << SLICE_BITS];
if (!(data->valid & (1 << slice)) ||
time_after(jiffies, data->last_updated[slice])) {
dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
data->valid &= ~(1 << slice);
addr = USER_EEPROM_BASE + (slice << SLICE_BITS);
/* select the eeprom address */
if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
dev_err(&client->dev, "address set failed\n");
goto exit_up;
}
if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
if (i2c_smbus_read_i2c_block_data(client,
MAX6875_CMD_BLK_READ,
buf) != SLICE_SIZE) {
goto exit_up;
}
} else {
for (i = 0; i < SLICE_SIZE; i++) {
j = i2c_smbus_read_byte(client);
if (j < 0) {
goto exit_up;
}
buf[i] = j;
}
}
data->last_updated[slice] = jiffies;
data->valid |= (1 << slice);
}
exit_up:
mutex_unlock(&data->update_lock);
}
static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct max6875_data *data = i2c_get_clientdata(client);
int slice, max_slice;
if (off > USER_EEPROM_SIZE)
return 0;
if (off + count > USER_EEPROM_SIZE)
count = USER_EEPROM_SIZE - off;
/* refresh slices which contain requested bytes */
max_slice = (off + count - 1) >> SLICE_BITS;
for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
max6875_update_slice(client, slice);
memcpy(buf, &data->data[off], count);
return count;
}
static struct bin_attribute user_eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
.owner = THIS_MODULE,
},
.size = USER_EEPROM_SIZE,
.read = max6875_read,
};
static int max6875_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, max6875_detect);
}
/* This function is called by i2c_probe */
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *real_client;
struct i2c_client *fake_client;
struct max6875_data *data;
int err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
| I2C_FUNC_SMBUS_READ_BYTE))
return 0;
/* Only check even addresses */
if (address & 1)
return 0;
if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
return -ENOMEM;
/* A fake client is created on the odd address */
if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
err = -ENOMEM;
goto exit_kfree1;
}
/* Init real i2c_client */
real_client = &data->client;
i2c_set_clientdata(real_client, data);
real_client->addr = address;
real_client->adapter = adapter;
real_client->driver = &max6875_driver;
real_client->flags = 0;
strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Init fake client data */
i2c_set_clientdata(fake_client, NULL);
fake_client->addr = address | 1;
fake_client->adapter = adapter;
fake_client->driver = &max6875_driver;
fake_client->flags = 0;
strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
/* Prevent 24RF08 corruption (in case of user error) */
i2c_smbus_write_quick(real_client, 0);
if ((err = i2c_attach_client(real_client)) != 0)
goto exit_kfree2;
if ((err = i2c_attach_client(fake_client)) != 0)
goto exit_detach1;
err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
if (err)
goto exit_detach2;
return 0;
exit_detach2:
i2c_detach_client(fake_client);
exit_detach1:
i2c_detach_client(real_client);
exit_kfree2:
kfree(fake_client);
exit_kfree1:
kfree(data);
return err;
}
/* Will be called for both the real client and the fake client */
static int max6875_detach_client(struct i2c_client *client)
{
int err;
struct max6875_data *data = i2c_get_clientdata(client);
/* data is NULL for the fake client */
if (data)
sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
err = i2c_detach_client(client);
if (err)
return err;
if (data) /* real client */
kfree(data);
else /* fake client */
kfree(client);
return 0;
}
static int __init max6875_init(void)
{
return i2c_add_driver(&max6875_driver);
}
static void __exit max6875_exit(void)
{
i2c_del_driver(&max6875_driver);
}
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
MODULE_DESCRIPTION("MAX6875 driver");
MODULE_LICENSE("GPL");
module_init(max6875_init);
module_exit(max6875_exit);

196
drivers/i2c/chips/pca9539.c Normal file
View File

@@ -0,0 +1,196 @@
/*
pca9539.c - 16-bit I/O port with interrupt and reset
Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
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; version 2 of the License.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(pca9539);
enum pca9539_cmd
{
PCA9539_INPUT_0 = 0,
PCA9539_INPUT_1 = 1,
PCA9539_OUTPUT_0 = 2,
PCA9539_OUTPUT_1 = 3,
PCA9539_INVERT_0 = 4,
PCA9539_INVERT_1 = 5,
PCA9539_DIRECTION_0 = 6,
PCA9539_DIRECTION_1 = 7,
};
static int pca9539_attach_adapter(struct i2c_adapter *adapter);
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind);
static int pca9539_detach_client(struct i2c_client *client);
/* This is the driver that will be inserted */
static struct i2c_driver pca9539_driver = {
.driver = {
.name = "pca9539",
},
.attach_adapter = pca9539_attach_adapter,
.detach_client = pca9539_detach_client,
};
struct pca9539_data {
struct i2c_client client;
};
/* following are the sysfs callback functions */
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
struct i2c_client *client = to_i2c_client(dev);
return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client,
psa->index));
}
static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
struct i2c_client *client = to_i2c_client(dev);
unsigned long val = simple_strtoul(buf, NULL, 0);
if (val > 0xff)
return -EINVAL;
i2c_smbus_write_byte_data(client, psa->index, val);
return count;
}
/* Define the device attributes */
#define PCA9539_ENTRY_RO(name, cmd_idx) \
static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx)
#define PCA9539_ENTRY_RW(name, cmd_idx) \
static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \
pca9539_store, cmd_idx)
PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0);
PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1);
PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0);
PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1);
PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0);
PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1);
PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0);
PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1);
static struct attribute *pca9539_attributes[] = {
&sensor_dev_attr_input0.dev_attr.attr,
&sensor_dev_attr_input1.dev_attr.attr,
&sensor_dev_attr_output0.dev_attr.attr,
&sensor_dev_attr_output1.dev_attr.attr,
&sensor_dev_attr_invert0.dev_attr.attr,
&sensor_dev_attr_invert1.dev_attr.attr,
&sensor_dev_attr_direction0.dev_attr.attr,
&sensor_dev_attr_direction1.dev_attr.attr,
NULL
};
static struct attribute_group pca9539_defattr_group = {
.attrs = pca9539_attributes,
};
static int pca9539_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, pca9539_detect);
}
/* This function is called by i2c_probe */
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct pca9539_data *data;
int err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
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 pca9539_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 = &pca9539_driver;
new_client->flags = 0;
if (kind < 0) {
/* Detection: the pca9539 only has 8 registers (0-7).
A read of 7 should succeed, but a read of 8 should fail. */
if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
(i2c_smbus_read_byte_data(new_client, 8) >= 0))
goto exit_kfree;
}
strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_kfree;
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj,
&pca9539_defattr_group);
if (err)
goto exit_detach;
return 0;
exit_detach:
i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
return err;
}
static int pca9539_detach_client(struct i2c_client *client)
{
int err;
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
if ((err = i2c_detach_client(client)))
return err;
kfree(i2c_get_clientdata(client));
return 0;
}
static int __init pca9539_init(void)
{
return i2c_add_driver(&pca9539_driver);
}
static void __exit pca9539_exit(void)
{
i2c_del_driver(&pca9539_driver);
}
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
MODULE_DESCRIPTION("PCA9539 driver");
MODULE_LICENSE("GPL");
module_init(pca9539_init);
module_exit(pca9539_exit);

233
drivers/i2c/chips/pcf8574.c Normal file
View File

@@ -0,0 +1,233 @@
/*
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[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
I2C_CLIENT_END };
/* 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);
static struct attribute *pcf8574_attributes[] = {
&dev_attr_read.attr,
&dev_attr_write.attr,
NULL
};
static const struct attribute_group pcf8574_attr_group = {
.attrs = pcf8574_attributes,
};
/*
* Real code
*/
static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, pcf8574_detect);
}
/* 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;
/* 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)))
goto exit_free;
/* Initialize the PCF8574 chip */
pcf8574_init_client(new_client);
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
if (err)
goto exit_detach;
return 0;
exit_detach:
i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
static int pcf8574_detach_client(struct i2c_client *client)
{
int err;
sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
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 = PCF8574_INIT;
i2c_smbus_write_byte(client, data->write);
}
static int __init pcf8574_init(void)
{
return i2c_add_driver(&pcf8574_driver);
}
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");
module_init(pcf8574_init);
module_exit(pcf8574_exit);

343
drivers/i2c/chips/pcf8591.c Normal file
View File

@@ -0,0 +1,343 @@
/*
pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(pcf8591);
static int input_mode;
module_param(input_mode, int, 0);
MODULE_PARM_DESC(input_mode,
"Analog input mode:\n"
" 0 = four single ended inputs\n"
" 1 = three differential inputs\n"
" 2 = single ended and differential mixed\n"
" 3 = two differential inputs\n");
/* The PCF8591 control byte
7 6 5 4 3 2 1 0
| 0 |AOEF| AIP | 0 |AINC| AICH | */
/* Analog Output Enable Flag (analog output active if 1) */
#define PCF8591_CONTROL_AOEF 0x40
/* Analog Input Programming
0x00 = four single ended inputs
0x10 = three differential inputs
0x20 = single ended and differential mixed
0x30 = two differential inputs */
#define PCF8591_CONTROL_AIP_MASK 0x30
/* Autoincrement Flag (switch on if 1) */
#define PCF8591_CONTROL_AINC 0x04
/* Channel selection
0x00 = channel 0
0x01 = channel 1
0x02 = channel 2
0x03 = channel 3 */
#define PCF8591_CONTROL_AICH_MASK 0x03
/* Initial values */
#define PCF8591_INIT_CONTROL ((input_mode << 4) | PCF8591_CONTROL_AOEF)
#define PCF8591_INIT_AOUT 0 /* DAC out = 0 */
/* Conversions */
#define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg))
struct pcf8591_data {
struct i2c_client client;
struct mutex update_lock;
u8 control;
u8 aout;
};
static int pcf8591_attach_adapter(struct i2c_adapter *adapter);
static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind);
static int pcf8591_detach_client(struct i2c_client *client);
static void pcf8591_init_client(struct i2c_client *client);
static int pcf8591_read_channel(struct device *dev, int channel);
/* This is the driver that will be inserted */
static struct i2c_driver pcf8591_driver = {
.driver = {
.name = "pcf8591",
},
.id = I2C_DRIVERID_PCF8591,
.attach_adapter = pcf8591_attach_adapter,
.detach_client = pcf8591_detach_client,
};
/* following are the sysfs callback functions */
#define show_in_channel(channel) \
static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\
} \
static DEVICE_ATTR(in##channel##_input, S_IRUGO, \
show_in##channel##_input, NULL);
show_in_channel(0);
show_in_channel(1);
show_in_channel(2);
show_in_channel(3);
static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n", data->aout * 10);
}
static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
unsigned int value;
struct i2c_client *client = to_i2c_client(dev);
struct pcf8591_data *data = i2c_get_clientdata(client);
if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) {
data->aout = value;
i2c_smbus_write_byte_data(client, data->control, data->aout);
return count;
}
return -EINVAL;
}
static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
show_out0_ouput, set_out0_output);
static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF)));
}
static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8591_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
if (val)
data->control |= PCF8591_CONTROL_AOEF;
else
data->control &= ~PCF8591_CONTROL_AOEF;
i2c_smbus_write_byte(client, data->control);
mutex_unlock(&data->update_lock);
return count;
}
static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
show_out0_enable, set_out0_enable);
static struct attribute *pcf8591_attributes[] = {
&dev_attr_out0_enable.attr,
&dev_attr_out0_output.attr,
&dev_attr_in0_input.attr,
&dev_attr_in1_input.attr,
NULL
};
static const struct attribute_group pcf8591_attr_group = {
.attrs = pcf8591_attributes,
};
static struct attribute *pcf8591_attributes_opt[] = {
&dev_attr_in2_input.attr,
&dev_attr_in3_input.attr,
NULL
};
static const struct attribute_group pcf8591_attr_group_opt = {
.attrs = pcf8591_attributes_opt,
};
/*
* Real code
*/
static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, pcf8591_detect);
}
/* This function is called by i2c_probe */
static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct pcf8591_data *data;
int err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
| I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
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 pcf8591_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 = &pcf8591_driver;
new_client->flags = 0;
/* Now, we would do the remaining detection. But the PCF8591 is plainly
impossible to detect! Stupid chip. */
/* Determine the chip type - only one kind supported! */
if (kind <= 0)
kind = pcf8591;
/* Fill in the remaining client fields and put it into the global
list */
strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_kfree;
/* Initialize the PCF8591 chip */
pcf8591_init_client(new_client);
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group);
if (err)
goto exit_detach;
/* Register input2 if not in "two differential inputs" mode */
if (input_mode != 3) {
if ((err = device_create_file(&new_client->dev,
&dev_attr_in2_input)))
goto exit_sysfs_remove;
}
/* Register input3 only in "four single ended inputs" mode */
if (input_mode == 0) {
if ((err = device_create_file(&new_client->dev,
&dev_attr_in3_input)))
goto exit_sysfs_remove;
}
return 0;
exit_sysfs_remove:
sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt);
sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group);
exit_detach:
i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
return err;
}
static int pcf8591_detach_client(struct i2c_client *client)
{
int err;
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
if ((err = i2c_detach_client(client)))
return err;
kfree(i2c_get_clientdata(client));
return 0;
}
/* Called when we have found a new PCF8591. */
static void pcf8591_init_client(struct i2c_client *client)
{
struct pcf8591_data *data = i2c_get_clientdata(client);
data->control = PCF8591_INIT_CONTROL;
data->aout = PCF8591_INIT_AOUT;
i2c_smbus_write_byte_data(client, data->control, data->aout);
/* The first byte transmitted contains the conversion code of the
previous read cycle. FLUSH IT! */
i2c_smbus_read_byte(client);
}
static int pcf8591_read_channel(struct device *dev, int channel)
{
u8 value;
struct i2c_client *client = to_i2c_client(dev);
struct pcf8591_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) {
data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
| channel;
i2c_smbus_write_byte(client, data->control);
/* The first byte transmitted contains the conversion code of
the previous read cycle. FLUSH IT! */
i2c_smbus_read_byte(client);
}
value = i2c_smbus_read_byte(client);
mutex_unlock(&data->update_lock);
if ((channel == 2 && input_mode == 2) ||
(channel != 3 && (input_mode == 1 || input_mode == 3)))
return (10 * REG_TO_SIGNED(value));
else
return (10 * value);
}
static int __init pcf8591_init(void)
{
if (input_mode < 0 || input_mode > 3) {
printk(KERN_WARNING "pcf8591: invalid input_mode (%d)\n",
input_mode);
input_mode = 0;
}
return i2c_add_driver(&pcf8591_driver);
}
static void __exit pcf8591_exit(void)
{
i2c_del_driver(&pcf8591_driver);
}
MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
MODULE_DESCRIPTION("PCF8591 driver");
MODULE_LICENSE("GPL");
module_init(pcf8591_init);
module_exit(pcf8591_exit);

View File

@@ -0,0 +1,348 @@
/*
eeprom.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com>
Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
Copyright (C) 2003 IBM Corp.
2004-01-16 Jean Delvare <khali@linux-fr.org>
Divide the eeprom in 32-byte (arbitrary) slices. This significantly
speeds sensors up, as well as various scripts using the eeprom
module.
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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include<linux/delay.h>
#include "../../input/touchscreen/s3c_ts_iic.h"
//Ivan 20090608 Ivan
#define ROTATE_NAGATIVE_90
//Ivan 20090608 Ivan
//Tony test
//#define QISDA_TEST_GPIO_PROBE
#include <asm/io.h>
/*kit.mod 20090811*/
#include "../../video/epaper.h"
/*kit.end*/
/* Addresses to scan */
#define QISDA_IIC_ID 0xB8
#define DELAY_TIME_IIC_READ 8//1//8
static struct i2c_driver qisda_iic_driver;
static unsigned short normal_i2c[] = { QISDA_IIC_ID>>1 , I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(qisda_iic);
typedef struct qisda_iic_data{
struct i2c_client client;
struct mutex update_lock;
u8 valid; /* bitfield, bit!=0 if slice is valid */
unsigned long last_updated[8]; /* In jiffies, 8 slices */
};
typedef struct {
unsigned char subaddr;
unsigned char value;
}qisda_iic_t;
qisda_iic_t qisda_iics_regs_mirror[2]=
{
{0x40,0xff},
{0x41,0xff},
};
static int qisda_iic_attach_adapter(struct i2c_adapter *adapter);
static int qisda_iic_detect(struct i2c_adapter *adapter, int address, int kind);
static int qisda_iic_detach_client(struct i2c_client *client);
unsigned char qisda_iic_read(struct i2c_client *client, unsigned char subaddr);
static int qisda_iic_write(struct i2c_client *client, unsigned char subaddr, unsigned char val);
static int qisda_iic_command(struct i2c_client *client, unsigned int cmd, void *arg);
//Tony test
#ifdef QISDA_TEST_GPIO_PROBE
static void __iomem *g_pGPIOReg_GPFCON;
#endif
/* This is the driver that will be inserted */
static struct i2c_driver qisda_iic_driver = {
.driver = {
.name = "qisda_iic",
},
.id = I2C_DRIVERID_QISDA_AUO,
.attach_adapter = qisda_iic_attach_adapter,
.detach_client = qisda_iic_detach_client,
.command =qisda_iic_command
};
#define TRUE 1
#define FALSE 0
//Tony 090615 start
#define NEW_TCOM_BOARD
//Tony 090615 end
unsigned char qisda_iic_read(struct i2c_client *client, unsigned char subaddr)
{
int ret;
unsigned char buf[1];
struct i2c_msg msg = { client->addr, 0, 1, buf };
buf[0] = subaddr;
//Tony test
#ifdef QISDA_TEST_GPIO_PROBE
writel(readl(g_pGPIOReg_GPFCON+0x04) & (0x0<<0), g_pGPIOReg_GPFCON+0x04);
#endif
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
if (ret == -EIO) {
printk(" I2C read Error, subaddr: 0x%x \n", subaddr);
return 0;
}
//Tony test
#ifdef QISDA_TEST_GPIO_PROBE
writel(readl(g_pGPIOReg_GPFCON+0x04) | (0x1<<0), g_pGPIOReg_GPFCON+0x04);
#endif
msg.flags = I2C_M_RD ;
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
//Tony test
#ifdef QISDA_TEST_GPIO_PROBE
writel(readl(g_pGPIOReg_GPFCON+0x04) & (0x0<<0), g_pGPIOReg_GPFCON+0x04);
#endif
return buf[0];
}
static int qisda_iic_write(struct i2c_client *client, unsigned char subaddr, unsigned char val)
{
unsigned char buf[2];
int ret;
struct i2c_msg msg = { client->addr, 0, 2, buf };
buf[0] = subaddr;
buf[1] = val;
ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
if(ret == -EIO){
printk(" I2C write Error, subaddr: 0x%x \n", subaddr);
}
return ret;
}
static int qisda_iic_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, qisda_iic_detect);
}
/* This function is called by i2c_probe */
static int qisda_iic_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct qisda_iic_data *data;
int err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) goto exit;
if (!(data = kzalloc(sizeof(struct qisda_iic_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 = &qisda_iic_driver;
new_client->flags = 0;
/* Fill in the remaining client fields */
strlcpy(new_client->name, "qisda_iic", I2C_NAME_SIZE);
data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client))) goto exit_kfree;
//Tell the s3c_ts_iic. It is ready to initialize the panel by setting interrupt mode.
//Then it will callback to the command
if ((err = s3c_ts_iic_port_init(new_client))) goto exit_kfree;;
return err;
exit_kfree:
i2c_detach_client(new_client);
kfree(data);
exit:
printk(KERN_INFO "qisda_iic_detect return error\n");
return err;
}
static int qisda_iic_detach_client(struct i2c_client *client)
{
int err;
err = i2c_detach_client(client);
if (err)
return err;
kfree(i2c_get_clientdata(client));
return 0;
}
static int qisda_iic_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
unsigned char u8return,u8x1,u8x0,u8y1,u8y0;
unsigned int *pos;
#define INT_MODE_ENABLE (1<<3)
#define INT_MODE_HIGH_ACTIVE (1<<2)
#define INT_MODE_TOUCH_INDICATE (1<<1)
#define INT_MODE_DIFFERENCE (1<<0)
switch(cmd)
{
case QISDA_IIC_INIT:
//Set interrupt mode. Enable interrupt, Low active.
//Tony test
#ifdef QISDA_TEST_GPIO_PROBE
g_pGPIOReg_GPFCON = ioremap(0x56000050, 0x00100000);
writel(readl(g_pGPIOReg_GPFCON) | (0x1<<0), g_pGPIOReg_GPFCON);
writel(readl(g_pGPIOReg_GPFCON+0x04) | (0x1<<0), g_pGPIOReg_GPFCON+0x04);
writel(readl(g_pGPIOReg_GPFCON+0x08) | (0x2<<0), g_pGPIOReg_GPFCON+0x08);
#endif
#ifdef NEW_TCOM_BOARD
//printk(KERN_INFO "qisda_iic_detect INIT 1111\n");
//mdelay(300);
//if(qisda_iic_write(client, 0x78, 0x3) < 0) return -EIO;
//mdelay(250);
//printk(KERN_INFO "qisda_iic_command INIT 2222\n");
if(qisda_iic_write(client, 0x71, 0xA) < 0) return -EIO;
udelay(DELAY_TIME_IIC_READ);
u8return= qisda_iic_read(client, 0x71);
printk(KERN_INFO "qisda_iic_command INIT =0x%x\n",u8return);
qisda_iic_write(client, 0x6F, 0x22);
qisda_iic_write(client, 0x70, 0x22);
#else // old
printk(KERN_INFO "qisda_iic_command INIT 1111\n");
mdelay(6000);
qisda_iic_write(client, 0x78, 0x3);
printk(KERN_INFO "qisda_iic_command INIT 2222\n");
qisda_iic_write(client, 0x71,INT_MODE_ENABLE | INT_MODE_TOUCH_INDICATE);
udelay(DELAY_TIME_IIC_READ);
u8return= qisda_iic_read(client, 0x71);
printk(KERN_INFO "qisda_iic_command INIT =0x%x\n",u8return);
#endif
break;
case QISDA_IIC_READ_POSITION:
pos = arg;
#ifdef NEW_TCOM_BOARD
u8x0= qisda_iic_read(client, 0x00);
udelay(DELAY_TIME_IIC_READ);
u8x1= qisda_iic_read(client, 0x01);
udelay(DELAY_TIME_IIC_READ);
u8y0= qisda_iic_read(client, 0x02);
udelay(DELAY_TIME_IIC_READ);
u8y1= qisda_iic_read(client, 0x03);
udelay(DELAY_TIME_IIC_READ);
#else
u8x0= qisda_iic_read(client, 0x54);
udelay(DELAY_TIME_IIC_READ);
u8x1= qisda_iic_read(client, 0x58);
udelay(DELAY_TIME_IIC_READ);
u8y0= qisda_iic_read(client, 0x55);
udelay(DELAY_TIME_IIC_READ);
u8y1= qisda_iic_read(client, 0x59);
#endif
udelay(DELAY_TIME_IIC_READ);
u8x1 &= 0x3;
u8y1 &= 0x3;
#ifdef ROTATE_NAGATIVE_90
pos[0] = (unsigned int)u8x1*256 + u8x0;
pos[1] = (unsigned int)u8y1*256+ u8y0;
if(!((pos[0] ==0) && (pos[1]==0)))
{
pos[1] = (unsigned int)u8x1*256 + u8x0 -1;
pos[0] = (unsigned int)u8y1*256+ u8y0;
/*kit.mod 20090811*/
#if defined(AUO_EPAPER_6_INCH)
pos[0] = 601 - pos[0] -1;
#elif defined(AUO_EPAPER_9_INCH)
pos[0] = 769 - pos[0] -1;
#endif
/*kit.end*/
}
#else
pos[0] = (unsigned int)u8x1*256 + u8x0;
pos[1] = (unsigned int)u8y1*256+ u8y0;
#endif
//printk("X: %d, Y: %d\n", pos[0], pos[1]);
break;
case QISDA_IIC_CALIBRATION:
if(qisda_iic_write(client, 0x78, 0x3) < 0){
printk("CALIBRATION ERROR!");
return -EIO;
}
msleep(300);
break;
case QISDA_IIC_ACTIVE_MODE:
printk("ACTIVE MODE\n");
qisda_iic_write(client, 0x73, 0x50);
msleep(5);
break;
case QISDA_IIC_SLEEP_MODE:
printk("SLEEP MODE\n");
qisda_iic_write(client, 0x73, 0x51);
msleep(5);
break;
case QISDA_IIC_DEEPSLEEP_MODE:
printk("DEEP SLEEP MODE\n");
qisda_iic_write(client, 0x73, 0x52);
msleep(5);
break;
default:
break;
}
return 0;
}
static int __init qisda_iic_init(void) { return i2c_add_driver(&qisda_iic_driver); }
static void __exit qisda_iic_exit(void) { i2c_del_driver(&qisda_iic_driver); }
MODULE_AUTHOR("Tony YC Huang@qisda.com");
MODULE_DESCRIPTION("IIC interface for Qisda");
MODULE_LICENSE("GPL");
module_init(qisda_iic_init);
module_exit(qisda_iic_exit);

1072
drivers/i2c/chips/tps65010.c Normal file

File diff suppressed because it is too large Load Diff