diff options
Diffstat (limited to 'drivers/i2c/chips')
| -rw-r--r-- | drivers/i2c/chips/Kconfig | 138 | ||||
| -rw-r--r-- | drivers/i2c/chips/Makefile | 21 | ||||
| -rw-r--r-- | drivers/i2c/chips/ds1337.c | 404 | ||||
| -rw-r--r-- | drivers/i2c/chips/ds1374.c | 258 | ||||
| -rw-r--r-- | drivers/i2c/chips/eeprom.c | 252 | ||||
| -rw-r--r-- | drivers/i2c/chips/isp1301_omap.c | 1659 | ||||
| -rw-r--r-- | drivers/i2c/chips/m41t00.c | 240 | ||||
| -rw-r--r-- | drivers/i2c/chips/max6875.c | 259 | ||||
| -rw-r--r-- | drivers/i2c/chips/pca9539.c | 187 | ||||
| -rw-r--r-- | drivers/i2c/chips/pcf8574.c | 221 | ||||
| -rw-r--r-- | drivers/i2c/chips/pcf8591.c | 310 | ||||
| -rw-r--r-- | drivers/i2c/chips/rtc8564.c | 385 | ||||
| -rw-r--r-- | drivers/i2c/chips/rtc8564.h | 78 | ||||
| -rw-r--r-- | drivers/i2c/chips/tps65010.c | 1069 | ||||
| -rw-r--r-- | drivers/i2c/chips/x1205.c | 698 |
15 files changed, 0 insertions, 6179 deletions
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig deleted file mode 100644 index f9fae28f561..00000000000 --- a/drivers/i2c/chips/Kconfig +++ /dev/null @@ -1,138 +0,0 @@ -# -# 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 - 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. - -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 - 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. - -config SENSORS_RTC8564 - tristate "Epson 8564 RTC chip" - depends on I2C && EXPERIMENTAL - help - If you say yes here you get support for the Epson 8564 RTC chip. - - This driver can also be built as a module. If so, the module - will be called i2c-rtc8564. - -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. - -config RTC_X1205_I2C - tristate "Xicor X1205 RTC chip" - depends on I2C && EXPERIMENTAL - help - If you say yes here you get support for the Xicor X1205 RTC chip. - - This driver can also be built as a module. If so, the module - will be called x1205. - -endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile deleted file mode 100644 index 46178b57b1f..00000000000 --- a/drivers/i2c/chips/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# 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_SENSORS_RTC8564) += rtc8564.o -obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o -obj-$(CONFIG_TPS65010) += tps65010.o -obj-$(CONFIG_RTC_X1205_I2C) += x1205.o - -ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) -EXTRA_CFLAGS += -DDEBUG -endif - diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c deleted file mode 100644 index 93d483b8b77..00000000000 --- a/drivers/i2c/chips/ds1337.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * 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[16]; - 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)); - 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); diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c deleted file mode 100644 index 0710b9da9d5..00000000000 --- a/drivers/i2c/chips/ds1374.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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> - -#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 DECLARE_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 */ - - down(&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--); - - up(&ds1374_mutex); - - if (t1 != t2) { - dev_warn(&save_client->dev, - "can't get consistent time from rtc chip\n"); - t1 = 0; - } - - return t1; -} - -static void ds1374_set_tlet(ulong arg) -{ - ulong t1, t2; - int limit = 10; /* arbitrary retry limit */ - - t1 = *(ulong *) arg; - - down(&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--); - - up(&ds1374_mutex); - - if (t1 != t2) - dev_warn(&save_client->dev, - "can't confirm time set from rtc chip\n"); -} - -static ulong new_time; - -static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, - (ulong) & new_time); - -int ds1374_set_rtc_time(ulong nowtime) -{ - new_time = nowtime; - - if (in_interrupt()) - tasklet_schedule(&ds1374_tasklet); - else - ds1374_set_tlet((ulong) & new_time); - - 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; - - 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)); - tasklet_kill(&ds1374_tasklet); - } - 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"); diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c deleted file mode 100644 index 41116b7947f..00000000000 --- a/drivers/i2c/chips/eeprom.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - 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/sched.h> -#include <linux/jiffies.h> -#include <linux/i2c.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 semaphore 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; - - down(&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: - up(&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; - init_MUTEX(&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 */ - sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); - - return 0; - -exit_kfree: - kfree(data); -exit: - return err; -} - -static int eeprom_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 __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); diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c deleted file mode 100644 index 1251c7fc18d..00000000000 --- a/drivers/i2c/chips/isp1301_omap.c +++ /dev/null @@ -1,1659 +0,0 @@ -/* - * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller - * - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2004 David Brownell - * - * 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. - */ -#undef DEBUG -#undef VERBOSE - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/usb_ch9.h> -#include <linux/usb_gadget.h> -#include <linux/usb.h> -#include <linux/usb_otg.h> -#include <linux/i2c.h> -#include <linux/workqueue.h> - -#include <asm/irq.h> -#include <asm/arch/usb.h> - - -#ifndef DEBUG -#undef VERBOSE -#endif - - -#define DRIVER_VERSION "24 August 2004" -#define DRIVER_NAME (isp1301_driver.name) - -MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver"); -MODULE_LICENSE("GPL"); - -struct isp1301 { - struct otg_transceiver otg; - struct i2c_client client; - void (*i2c_release)(struct device *dev); - - int irq; - - u32 last_otg_ctrl; - unsigned working:1; - - struct timer_list timer; - - /* use keventd context to change the state for us */ - struct work_struct work; - - unsigned long todo; -# define WORK_UPDATE_ISP 0 /* update ISP from OTG */ -# define WORK_UPDATE_OTG 1 /* update OTG from ISP */ -# define WORK_HOST_RESUME 4 /* resume host */ -# define WORK_TIMER 6 /* timer fired */ -# define WORK_STOP 7 /* don't resubmit */ -}; - - -/* bits in OTG_CTRL_REG */ - -#define OTG_XCEIV_OUTPUTS \ - (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) -#define OTG_XCEIV_INPUTS \ - (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) -#define OTG_CTRL_BITS \ - (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) - /* and OTG_PULLUP is sometimes written */ - -#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ - OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ - OTG_CTRL_BITS) - - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_MACH_OMAP_H2 - -/* board-specific PM hooks */ - -#include <asm/arch/gpio.h> -#include <asm/arch/mux.h> -#include <asm/mach-types.h> - - -#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) - -#include <asm/arch/tps65010.h> - -#else - -static inline int tps65010_set_vbus_draw(unsigned mA) -{ - pr_debug("tps65010: draw %d mA (STUB)\n", mA); - return 0; -} - -#endif - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - int status = tps65010_set_vbus_draw(mA); - if (status < 0) - pr_debug(" VBUS %d mA error %d\n", mA, status); -} - -static void enable_vbus_source(struct isp1301 *isp) -{ - /* this board won't supply more than 8mA vbus power. - * some boards can switch a 100ma "unit load" (or more). - */ -} - - -/* products will deliver OTG messages with LEDs, GUI, etc */ -static inline void notresponding(struct isp1301 *isp) -{ - printk(KERN_NOTICE "OTG device not responding.\n"); -} - - -#endif - -/*-------------------------------------------------------------------------*/ - -/* only two addresses possible */ -#define ISP_BASE 0x2c -static unsigned short normal_i2c[] = { - ISP_BASE, ISP_BASE + 1, - I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - -static struct i2c_driver isp1301_driver; - -/* smbus apis are used for portability */ - -static inline u8 -isp1301_get_u8(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_byte_data(&isp->client, reg + 0); -} - -static inline int -isp1301_get_u16(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_word_data(&isp->client, reg); -} - -static inline int -isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits); -} - -static inline int -isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits); -} - -/*-------------------------------------------------------------------------*/ - -/* identification */ -#define ISP1301_VENDOR_ID 0x00 /* u16 read */ -#define ISP1301_PRODUCT_ID 0x02 /* u16 read */ -#define ISP1301_BCD_DEVICE 0x14 /* u16 read */ - -#define I2C_VENDOR_ID_PHILIPS 0x04cc -#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301 - -/* operational registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ -# define MC1_SPEED_REG (1 << 0) -# define MC1_SUSPEND_REG (1 << 1) -# define MC1_DAT_SE0 (1 << 2) -# define MC1_TRANSPARENT (1 << 3) -# define MC1_BDIS_ACON_EN (1 << 4) -# define MC1_OE_INT_EN (1 << 5) -# define MC1_UART_EN (1 << 6) -# define MC1_MASK 0x7f -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ -# define MC2_GLOBAL_PWR_DN (1 << 0) -# define MC2_SPD_SUSP_CTRL (1 << 1) -# define MC2_BI_DI (1 << 2) -# define MC2_TRANSP_BDIR0 (1 << 3) -# define MC2_TRANSP_BDIR1 (1 << 4) -# define MC2_AUDIO_EN (1 << 5) -# define MC2_PSW_EN (1 << 6) -# define MC2_EN2V7 (1 << 7) -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */ -#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */ - -#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */ -#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */ - -/* same bitfields in all interrupt registers */ -# define INTR_VBUS_VLD (1 << 0) -# define INTR_SESS_VLD (1 << 1) -# define INTR_DP_HI (1 << 2) -# define INTR_ID_GND (1 << 3) -# define INTR_DM_HI (1 << 4) -# define INTR_ID_FLOAT (1 << 5) -# define INTR_BDIS_ACON (1 << 6) -# define INTR_CR_INT (1 << 7) - -/*-------------------------------------------------------------------------*/ - -static const char *state_string(enum usb_otg_state state) -{ - switch (state) { - case OTG_STATE_A_IDLE: return "a_idle"; - case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; - case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; - case OTG_STATE_A_HOST: return "a_host"; - case OTG_STATE_A_SUSPEND: return "a_suspend"; - case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; - case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; - case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; - case OTG_STATE_B_IDLE: return "b_idle"; - case OTG_STATE_B_SRP_INIT: return "b_srp_init"; - case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; - case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; - case OTG_STATE_B_HOST: return "b_host"; - default: return "UNDEFINED"; - } -} - -static inline const char *state_name(struct isp1301 *isp) -{ - return state_string(isp->otg.state); -} - -#ifdef VERBOSE -#define dev_vdbg dev_dbg -#else -#define dev_vdbg(dev, fmt, arg...) do{}while(0) -#endif - -/*-------------------------------------------------------------------------*/ - -/* NOTE: some of this ISP1301 setup is specific to H2 boards; - * not everything is guarded by board-specific checks, or even using - * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI. - * - * ALSO: this currently doesn't use ISP1301 low-power modes - * while OTG is running. - */ - -static void power_down(struct isp1301 *isp) -{ - isp->otg.state = OTG_STATE_UNDEFINED; - - // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG); - - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -static void power_up(struct isp1301 *isp) -{ - // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG); - - /* do this only when cpu is driving transceiver, - * so host won't see a low speed device... - */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -#define NO_HOST_SUSPEND - -static int host_suspend(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->otg.host) - return -ENODEV; - - /* Currently ASSUMES only the OTG port matters; - * other ports could be active... - */ - dev = isp->otg.host->controller; - return dev->driver->suspend(dev, 3, 0); -#endif -} - -static int host_resume(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->otg.host) - return -ENODEV; - - dev = isp->otg.host->controller; - return dev->driver->resume(dev, 0); -#endif -} - -static int gadget_suspend(struct isp1301 *isp) -{ - isp->otg.gadget->b_hnp_enable = 0; - isp->otg.gadget->a_hnp_support = 0; - isp->otg.gadget->a_alt_hnp_support = 0; - return usb_gadget_vbus_disconnect(isp->otg.gadget); -} - -/*-------------------------------------------------------------------------*/ - -#define TIMER_MINUTES 10 -#define TIMER_JIFFIES (TIMER_MINUTES * 60 * HZ) - -/* Almost all our I2C messaging comes from a work queue's task context. - * NOTE: guaranteeing certain response times might mean we shouldn't - * share keventd's work queue; a realtime task might be safest. - */ -void -isp1301_defer_work(struct isp1301 *isp, int work) -{ - int status; - - if (isp && !test_and_set_bit(work, &isp->todo)) { - (void) get_device(&isp->client.dev); - status = schedule_work(&isp->work); - if (!status && !isp->working) - dev_vdbg(&isp->client.dev, - "work item %d may be lost\n", work); - } -} - -/* called from irq handlers */ -static void a_idle(struct isp1301 *isp, const char *tag) -{ - if (isp->otg.state == OTG_STATE_A_IDLE) - return; - - isp->otg.default_a = 1; - if (isp->otg.host) { - isp->otg.host->is_b_host = 0; - host_suspend(isp); - } - if (isp->otg.gadget) { - isp->otg.gadget->is_a_peripheral = 1; - gadget_suspend(isp); - } - isp->otg.state = OTG_STATE_A_IDLE; - isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -/* called from irq handlers */ -static void b_idle(struct isp1301 *isp, const char *tag) -{ - if (isp->otg.state == OTG_STATE_B_IDLE) - return; - - isp->otg.default_a = 0; - if (isp->otg.host) { - isp->otg.host->is_b_host = 1; - host_suspend(isp); - } - if (isp->otg.gadget) { - isp->otg.gadget->is_a_peripheral = 0; - gadget_suspend(isp); - } - isp->otg.state = OTG_STATE_B_IDLE; - isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -static void -dump_regs(struct isp1301 *isp, const char *label) -{ -#ifdef DEBUG - u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); - u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - - pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n", - OTG_CTRL_REG, label, state_name(isp), - ctrl, status, src); - /* mode control and irq enables don't change much */ -#endif -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_OTG - -/* - * The OMAP OTG controller handles most of the OTG state transitions. - * - * We translate isp1301 outputs (mostly voltage comparator status) into - * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state - * flags into isp1301 inputs ... and infer state transitions. - */ - -#ifdef VERBOSE - -static void check_state(struct isp1301 *isp, const char *tag) -{ - enum usb_otg_state state = OTG_STATE_UNDEFINED; - u8 fsm = OTG_TEST_REG & 0x0ff; - unsigned extra = 0; - - switch (fsm) { - - /* default-b */ - case 0x0: - state = OTG_STATE_B_IDLE; - break; - case 0x3: - case 0x7: - extra = 1; - case 0x1: - state = OTG_STATE_B_PERIPHERAL; - break; - case 0x11: - state = OTG_STATE_B_SRP_INIT; - break; - - /* extra dual-role default-b states */ - case 0x12: - case 0x13: - case 0x16: - extra = 1; - case 0x17: - state = OTG_STATE_B_WAIT_ACON; - break; - case 0x34: - state = OTG_STATE_B_HOST; - break; - - /* default-a */ - case 0x36: - state = OTG_STATE_A_IDLE; - break; - case 0x3c: - state = OTG_STATE_A_WAIT_VFALL; - break; - case 0x7d: - state = OTG_STATE_A_VBUS_ERR; - break; - case 0x9e: - case 0x9f: - extra = 1; - case 0x89: - state = OTG_STATE_A_PERIPHERAL; - break; - case 0xb7: - state = OTG_STATE_A_WAIT_VRISE; - break; - case 0xb8: - state = OTG_STATE_A_WAIT_BCON; - break; - case 0xb9: - state = OTG_STATE_A_HOST; - break; - case 0xba: - state = OTG_STATE_A_SUSPEND; - break; - default: - break; - } - if (isp->otg.state == state && !extra) - return; - pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, - state_string(state), fsm, state_name(isp), OTG_CTRL_REG); -} - -#else - -static inline void check_state(struct isp1301 *isp, const char *tag) { } - -#endif - -/* outputs from ISP1301_INTERRUPT_SOURCE */ -static void update_otg1(struct isp1301 *isp, u8 int_src) -{ - u32 otg_ctrl; - - otg_ctrl = OTG_CTRL_REG - & OTG_CTRL_MASK - & ~OTG_XCEIV_INPUTS - & ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD); - if (int_src & INTR_SESS_VLD) - otg_ctrl |= OTG_ASESSVLD; - else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) { - a_idle(isp, "vfall"); - otg_ctrl &= ~OTG_CTRL_BITS; - } - if (int_src & INTR_VBUS_VLD) - otg_ctrl |= OTG_VBUSVLD; - if (int_src & INTR_ID_GND) { /* default-A */ - if (isp->otg.state == OTG_STATE_B_IDLE - || isp->otg.state == OTG_STATE_UNDEFINED) { - a_idle(isp, "init"); - return; - } - } else { /* default-B */ - otg_ctrl |= OTG_ID; - if (isp->otg.state == OTG_STATE_A_IDLE - || isp->otg.state == OTG_STATE_UNDEFINED) { - b_idle(isp, "init"); - return; - } - } - OTG_CTRL_REG = otg_ctrl; -} - -/* outputs from ISP1301_OTG_STATUS */ -static void update_otg2(struct isp1301 *isp, u8 otg_status) -{ - u32 otg_ctrl; - - otg_ctrl = OTG_CTRL_REG - & OTG_CTRL_MASK - & ~OTG_XCEIV_INPUTS - & ~(OTG_BSESSVLD|OTG_BSESSEND); - if (otg_status & OTG_B_SESS_VLD) - otg_ctrl |= OTG_BSESSVLD; - else if (otg_status & OTG_B_SESS_END) - otg_ctrl |= OTG_BSESSEND; - OTG_CTRL_REG = otg_ctrl; -} - -/* inputs going to ISP1301 */ -static void otg_update_isp(struct isp1301 *isp) -{ - u32 otg_ctrl, otg_change; - u8 set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP; - - otg_ctrl = OTG_CTRL_REG; - otg_change = otg_ctrl ^ isp->last_otg_ctrl; - isp->last_otg_ctrl = otg_ctrl; - otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; - - switch (isp->otg.state) { - case OTG_STATE_B_IDLE: - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_SRP_INIT: - if (!(otg_ctrl & OTG_PULLUP)) { - // if (otg_ctrl & OTG_B_HNPEN) { - if (isp->otg.gadget->b_hnp_enable) { - isp->otg.state = OTG_STATE_B_WAIT_ACON; - pr_debug(" --> b_wait_acon\n"); - } - goto pulldown; - } -pullup: - set |= OTG1_DP_PULLUP; - clr |= OTG1_DP_PULLDOWN; - break; - case OTG_STATE_A_SUSPEND: - case OTG_STATE_A_PERIPHERAL: - if (otg_ctrl & OTG_PULLUP) - goto pullup; - /* FALLTHROUGH */ - // case OTG_STATE_B_WAIT_ACON: - default: -pulldown: - set |= OTG1_DP_PULLDOWN; - clr |= OTG1_DP_PULLUP; - break; - } - -# define toggle(OTG,ISP) do { \ - if (otg_ctrl & OTG) set |= ISP; \ - else clr |= ISP; \ - } while (0) - - if (!(isp->otg.host)) - otg_ctrl &= ~OTG_DRV_VBUS; - - switch (isp->otg.state) { - case OTG_STATE_A_SUSPEND: - if (otg_ctrl & OTG_DRV_VBUS) { - set |= OTG1_VBUS_DRV; - break; - } - /* HNP failed for some reason (A_AIDL_BDIS timeout) */ - notresponding(isp); - - /* FALLTHROUGH */ - case OTG_STATE_A_VBUS_ERR: - isp->otg.state = OTG_STATE_A_WAIT_VFALL; - pr_debug(" --> a_wait_vfall\n"); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_VFALL: - /* FIXME usbcore thinks port power is still on ... */ - clr |= OTG1_VBUS_DRV; - break; - case OTG_STATE_A_IDLE: - if (otg_ctrl & OTG_DRV_VBUS) { - isp->otg.state = OTG_STATE_A_WAIT_VRISE; - pr_debug(" --> a_wait_vrise\n"); - } - /* FALLTHROUGH */ - default: - toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); - } - - toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG); - toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG); - -# undef toggle - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr); - - /* HNP switch to host or peripheral; and SRP */ - if (otg_change & OTG_PULLUP) { - switch (isp->otg.state) { - case OTG_STATE_B_IDLE: - if (clr & OTG1_DP_PULLUP) - break; - isp->otg.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - break; - case OTG_STATE_A_SUSPEND: - if (clr & OTG1_DP_PULLUP) - break; - isp->otg.state = OTG_STATE_A_PERIPHERAL; - pr_debug(" --> a_peripheral\n"); - break; - default: - break; - } - OTG_CTRL_REG |= OTG_PULLUP; - } - - check_state(isp, __FUNCTION__); - dump_regs(isp, "otg->isp1301"); -} - -static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs) -{ - u16 otg_irq = OTG_IRQ_SRC_REG; - u32 otg_ctrl; - int ret = IRQ_NONE; - struct isp1301 *isp = _isp; - - /* update ISP1301 transciever from OTG controller */ - if (otg_irq & OPRT_CHG) { - OTG_IRQ_SRC_REG = OPRT_CHG; - isp1301_defer_work(isp, WORK_UPDATE_ISP); - ret = IRQ_HANDLED; - - /* SRP to become b_peripheral failed */ - } else if (otg_irq & B_SRP_TMROUT) { - pr_debug("otg: B_SRP_TIMEOUT, %06x\n", OTG_CTRL_REG); - notresponding(isp); - - /* gadget drivers that care should monitor all kinds of - * remote wakeup (SRP, normal) using their own timer - * to give "check cable and A-device" messages. - */ - if (isp->otg.state == OTG_STATE_B_SRP_INIT) - b_idle(isp, "srp_timeout"); - - OTG_IRQ_SRC_REG = B_SRP_TMROUT; - ret = IRQ_HANDLED; - - /* HNP to become b_host failed */ - } else if (otg_irq & B_HNP_FAIL) { - pr_debug("otg: %s B_HNP_FAIL, %06x\n", - state_name(isp), OTG_CTRL_REG); - notresponding(isp); - - otg_ctrl = OTG_CTRL_REG; - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - OTG_CTRL_REG = otg_ctrl; - - /* subset of b_peripheral()... */ - isp->otg.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - - OTG_IRQ_SRC_REG = B_HNP_FAIL; - ret = IRQ_HANDLED; - - /* detect SRP from B-device ... */ - } else if (otg_irq & A_SRP_DETECT) { - pr_debug("otg: %s SRP_DETECT, %06x\n", - state_name(isp), OTG_CTRL_REG); - - isp1301_defer_work(isp, WORK_UPDATE_OTG); - switch (isp->otg.state) { - case OTG_STATE_A_IDLE: - if (!isp->otg.host) - break; - isp1301_defer_work(isp, WORK_HOST_RESUME); - otg_ctrl = OTG_CTRL_REG; - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & ~OTG_XCEIV_INPUTS - & OTG_CTRL_MASK; - OTG_CTRL_REG = otg_ctrl; - break; - default: - break; - } - - OTG_IRQ_SRC_REG = A_SRP_DETECT; - ret = IRQ_HANDLED; - - /* timer expired: T(a_wait_bcon) and maybe T(a_wait_vrise) - * we don't track them separately - */ - } else if (otg_irq & A_REQ_TMROUT) { - otg_ctrl = OTG_CTRL_REG; - pr_info("otg: BCON_TMOUT from %s, %06x\n", - state_name(isp), otg_ctrl); - notresponding(isp); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - OTG_CTRL_REG = otg_ctrl; - isp->otg.state = OTG_STATE_A_WAIT_VFALL; - - OTG_IRQ_SRC_REG = A_REQ_TMROUT; - ret = IRQ_HANDLED; - - /* A-supplied voltage fell too low; overcurrent */ - } else if (otg_irq & A_VBUS_ERR) { - otg_ctrl = OTG_CTRL_REG; - printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n", - state_name(isp), otg_irq, otg_ctrl); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - OTG_CTRL_REG = otg_ctrl; - isp->otg.state = OTG_STATE_A_VBUS_ERR; - - OTG_IRQ_SRC_REG = A_VBUS_ERR; - ret = IRQ_HANDLED; - - /* switch driver; the transciever code activates it, - * ungating the udc clock or resuming OHCI. - */ - } else if (otg_irq & DRIVER_SWITCH) { - int kick = 0; - - otg_ctrl = OTG_CTRL_REG; - printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n", - state_name(isp), - (otg_ctrl & OTG_DRIVER_SEL) - ? "gadget" : "host", - otg_ctrl); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is peripheral */ - if (otg_ctrl & OTG_DRIVER_SEL) { - switch (isp->otg.state) { - case OTG_STATE_A_IDLE: - b_idle(isp, __FUNCTION__); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is host */ - } else { - if (!(otg_ctrl & OTG_ID)) { - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ; - } - - if (isp->otg.host) { - switch (isp->otg.state) { - case OTG_STATE_B_WAIT_ACON: - isp->otg.state = OTG_STATE_B_HOST; - pr_debug(" --> b_host\n"); - kick = 1; - break; - case OTG_STATE_A_WAIT_BCON: - isp->otg.state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - break; - case OTG_STATE_A_PERIPHERAL: - isp->otg.state = OTG_STATE_A_WAIT_BCON; - pr_debug(" --> a_wait_bcon\n"); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_HOST_RESUME); - } - } - - OTG_IRQ_SRC_REG = DRIVER_SWITCH; - ret = IRQ_HANDLED; - - if (kick) - usb_bus_start_enum(isp->otg.host, - isp->otg.host->otg_port); - } - - check_state(isp, __FUNCTION__); - return ret; -} - -static struct platform_device *otg_dev; - -static int otg_init(struct isp1301 *isp) -{ - if (!otg_dev) - return -ENODEV; - - dump_regs(isp, __FUNCTION__); - /* some of these values are board-specific... */ - OTG_SYSCON_2_REG |= OTG_EN - /* for B-device: */ - | SRP_GPDATA /* 9msec Bdev D+ pulse */ - | SRP_GPDVBUS /* discharge after VBUS pulse */ - // | (3 << 24) /* 2msec VBUS pulse */ - /* for A-device: */ - | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */ - | SRP_DPW /* detect 167+ns SRP pulses */ - | SRP_DATA | SRP_VBUS /* accept both kinds of SRP pulse */ - ; - - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); - - check_state(isp, __FUNCTION__); - pr_debug("otg: %s, %s %06x\n", - state_name(isp), __FUNCTION__, OTG_CTRL_REG); - - OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG - | B_SRP_TMROUT | B_HNP_FAIL - | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT; - OTG_SYSCON_2_REG |= OTG_EN; - - return 0; -} - -static int otg_probe(struct platform_device *dev) -{ - // struct omap_usb_config *config = dev->platform_data; - - otg_dev = dev; - return 0; -} - -static int otg_remove(struct platform_device *dev) -{ - otg_dev = 0; - return 0; -} - -struct platform_driver omap_otg_driver = { - .probe = otg_probe, - .remove = otg_remove, - .driver = { - .owner = THIS_MODULE, - .name = "omap_otg", - }, -}; - -static int otg_bind(struct isp1301 *isp) -{ - int status; - - if (otg_dev) - return -EBUSY; - - status = platform_driver_register(&omap_otg_driver); - if (status < 0) - return status; - - if (otg_dev) - status = request_irq(otg_dev->resource[1].start, omap_otg_irq, - SA_INTERRUPT, DRIVER_NAME, isp); - else - status = -ENODEV; - - if (status < 0) - platform_driver_unregister(&omap_otg_driver); - return status; -} - -static void otg_unbind(struct isp1301 *isp) -{ - if (!otg_dev) - return; - free_irq(otg_dev->resource[1].start, isp); -} - -#else - -/* OTG controller isn't clocked */ - -#endif /* CONFIG_USB_OTG */ - -/*-------------------------------------------------------------------------*/ - -static void b_peripheral(struct isp1301 *isp) -{ - OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; - usb_gadget_vbus_connect(isp->otg.gadget); - -#ifdef CONFIG_USB_OTG - enable_vbus_draw(isp, 8); - otg_update_isp(isp); -#else - enable_vbus_draw(isp, 100); - /* UDC driver just set OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); - isp->otg.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - dump_regs(isp, "2periph"); -#endif -} - -static void isp_update_otg(struct isp1301 *isp, u8 stat) -{ - u8 isp_stat, isp_bstat; - enum usb_otg_state state = isp->otg.state; - - if (stat & INTR_BDIS_ACON) - pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); - - /* start certain state transitions right away */ - isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - if (isp_stat & INTR_ID_GND) { - if (isp->otg.default_a) { - switch (state) { - case OTG_STATE_B_IDLE: - a_idle(isp, "idle"); - /* FALLTHROUGH */ - case OTG_STATE_A_IDLE: - enable_vbus_source(isp); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_VRISE: - /* we skip over OTG_STATE_A_WAIT_BCON, since - * the HC will transition to A_HOST (or - * A_SUSPEND!) without our noticing except - * when HNP is used. - */ - if (isp_stat & INTR_VBUS_VLD) - isp->otg.state = OTG_STATE_A_HOST; - break; - case OTG_STATE_A_WAIT_VFALL: - if (!(isp_stat & INTR_SESS_VLD)) - a_idle(isp, "vfell"); - break; - default: - if (!(isp_stat & INTR_VBUS_VLD)) - isp->otg.state = OTG_STATE_A_VBUS_ERR; - break; - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - } else { - switch (state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_HOST: - case OTG_STATE_B_WAIT_ACON: - usb_gadget_vbus_disconnect(isp->otg.gadget); - break; - default: - break; - } - if (state != OTG_STATE_A_IDLE) - a_idle(isp, "id"); - if (isp->otg.host && state == OTG_STATE_A_IDLE) - isp1301_defer_work(isp, WORK_HOST_RESUME); - isp_bstat = 0; - } - } else { - /* if user unplugged mini-A end of cable, - * don't bypass A_WAIT_VFALL. - */ - if (isp->otg.default_a) { - switch (state) { - default: - isp->otg.state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_A_WAIT_VFALL: - state = OTG_STATE_A_IDLE; - /* khubd may take a while to notice and - * handle this disconnect, so don't go - * to B_IDLE quite yet. - */ - break; - case OTG_STATE_A_IDLE: - host_suspend(isp); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); - isp->otg.state = OTG_STATE_B_IDLE; - OTG_CTRL_REG &= OTG_CTRL_REG & OTG_CTRL_MASK - & ~OTG_CTRL_BITS; - break; - case OTG_STATE_B_IDLE: - break; - } - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - - switch (isp->otg.state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_HOST: - if (likely(isp_bstat & OTG_B_SESS_VLD)) - break; - enable_vbus_draw(isp, 0); -#ifndef CONFIG_USB_OTG - /* UDC driver will clear OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLUP); - dump_regs(isp, __FUNCTION__); -#endif - /* FALLTHROUGH */ - case OTG_STATE_B_SRP_INIT: - b_idle(isp, __FUNCTION__); - OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; - /* FALLTHROUGH */ - case OTG_STATE_B_IDLE: - if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) { -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); -#endif - b_peripheral(isp); - } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD))) - isp_bstat |= OTG_B_SESS_END; - break; - case OTG_STATE_A_WAIT_VFALL: - break; - default: - pr_debug("otg: unsupported b-device %s\n", - state_name(isp)); - break; - } - } - - if (state != isp->otg.state) - pr_debug(" isp, %s -> %s\n", - state_string(state), state_name(isp)); - -#ifdef CONFIG_USB_OTG - /* update the OTG controller state to match the isp1301; may - * trigger OPRT_CHG irqs for changes going to the isp1301. - */ - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); - check_state(isp, __FUNCTION__); -#endif - - dump_regs(isp, "isp1301->otg"); -} - -/*-------------------------------------------------------------------------*/ - -static u8 isp1301_clear_latch(struct isp1301 *isp) -{ - u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch); - return latch; -} - -static void -isp1301_work(void *data) -{ - struct isp1301 *isp = data; - int stop; - - /* implicit lock: we're the only task using this device */ - isp->working = 1; - do { - stop = test_bit(WORK_STOP, &isp->todo); - -#ifdef CONFIG_USB_OTG - /* transfer state from otg engine to isp1301 */ - if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) { - otg_update_isp(isp); - put_device(&isp->client.dev); - } -#endif - /* transfer state from isp1301 to otg engine */ - if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) { - u8 stat = isp1301_clear_latch(isp); - - isp_update_otg(isp, stat); - put_device(&isp->client.dev); - } - - if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) { - u32 otg_ctrl; - - /* - * skip A_WAIT_VRISE; hc transitions invisibly - * skip A_WAIT_BCON; same. - */ - switch (isp->otg.state) { - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - isp->otg.state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - otg_ctrl = OTG_CTRL_REG; - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & OTG_CTRL_MASK; - OTG_CTRL_REG = otg_ctrl; - break; - case OTG_STATE_B_WAIT_ACON: - isp->otg.state = OTG_STATE_B_HOST; - pr_debug(" --> b_host (acon)\n"); - break; - case OTG_STATE_B_HOST: - case OTG_STATE_B_IDLE: - case OTG_STATE_A_IDLE: - break; - default: - pr_debug(" host resume in %s\n", - state_name(isp)); - } - host_resume(isp); - // mdelay(10); - put_device(&isp->client.dev); - } - - if (test_and_clear_bit(WORK_TIMER, &isp->todo)) { -#ifdef VERBOSE - dump_regs(isp, "timer"); - if (!stop) - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); -#endif - put_device(&isp->client.dev); - } - - if (isp->todo) - dev_vdbg(&isp->client.dev, - "work done, todo = 0x%lx\n", - isp->todo); - if (stop) { - dev_dbg(&isp->client.dev, "stop\n"); - break; - } - } while (isp->todo); - isp->working = 0; -} - -static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs) -{ - isp1301_defer_work(isp, WORK_UPDATE_OTG); - return IRQ_HANDLED; -} - -static void isp1301_timer(unsigned long _isp) -{ - isp1301_defer_work((void *)_isp, WORK_TIMER); -} - -/*-------------------------------------------------------------------------*/ - -static void isp1301_release(struct device *dev) -{ - struct isp1301 *isp; - - isp = container_of(dev, struct isp1301, client.dev); - - /* ugly -- i2c hijacks our memory hook to wait_for_completion() */ - if (isp->i2c_release) - isp->i2c_release(dev); - kfree (isp); -} - -static struct isp1301 *the_transceiver; - -static int isp1301_detach_client(struct i2c_client *i2c) -{ - struct isp1301 *isp; - - isp = container_of(i2c, struct isp1301, client); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - free_irq(isp->irq, isp); -#ifdef CONFIG_USB_OTG - otg_unbind(isp); -#endif - if (machine_is_omap_h2()) - omap_free_gpio(2); - - isp->timer.data = 0; - set_bit(WORK_STOP, &isp->todo); - del_timer_sync(&isp->timer); - flush_scheduled_work(); - - put_device(&i2c->dev); - the_transceiver = 0; - - return i2c_detach_client(i2c); -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: three modes are possible here, only one of which - * will be standards-conformant on any given system: - * - * - OTG mode (dual-role), required if there's a Mini-AB connector - * - HOST mode, for when there's one or more A (host) connectors - * - DEVICE mode, for when there's a B/Mini-B (device) connector - * - * As a rule, you won't have an isp1301 chip unless it's there to - * support the OTG mode. Other modes help testing USB controllers - * in isolation from (full) OTG support, or maybe so later board - * revisions can help to support those feature. - */ - -#ifdef CONFIG_USB_OTG - -static int isp1301_otg_enable(struct isp1301 *isp) -{ - power_up(isp); - otg_init(isp); - - /* NOTE: since we don't change this, this provides - * a few more interrupts than are strictly needed. - */ - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - - dev_info(&isp->client.dev, "ready for dual-role USB ...\n"); - - return 0; -} - -#endif - -/* add or disable the host device+driver */ -static int -isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) -{ - struct isp1301 *isp = container_of(otg, struct isp1301, otg); - - if (!otg || isp != the_transceiver) - return -ENODEV; - - if (!host) { - OTG_IRQ_EN_REG = 0; - power_down(isp); - isp->otg.host = 0; - return 0; - } - -#ifdef CONFIG_USB_OTG - isp->otg.host = host; - dev_dbg(&isp->client.dev, "registered host\n"); - host_suspend(isp); - if (isp->otg.gadget) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_GADGET_OMAP) - // FIXME update its refcount - isp->otg.host = host; - - power_up(isp); - - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - dev_info(&isp->client.dev, "A-Host sessions ok\n"); - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_ID_GND); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, especially with - * the Mini-A end of an OTG cable. (Or something nonstandard - * like MiniB-to-StandardB, maybe built with a gender mender.) - */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); - - dump_regs(isp, __FUNCTION__); - - return 0; - -#else - dev_dbg(&isp->client.dev, "host sessions not allowed\n"); - return -EINVAL; -#endif - -} - -static int -isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) -{ - struct isp1301 *isp = container_of(otg, struct isp1301, otg); - - if (!otg || isp != the_transceiver) - return -ENODEV; - - if (!gadget) { - OTG_IRQ_EN_REG = 0; - if (!isp->otg.default_a) - enable_vbus_draw(isp, 0); - usb_gadget_vbus_disconnect(isp->otg.gadget); - isp->otg.gadget = 0; - power_down(isp); - return 0; - } - -#ifdef CONFIG_USB_OTG - isp->otg.gadget = gadget; - dev_dbg(&isp->client.dev, "registered gadget\n"); - /* gadget driver may be suspended until vbus_connect () */ - if (isp->otg.host) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE) - isp->otg.gadget = gadget; - // FIXME update its refcount - - OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK - & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS)) - | OTG_ID; - power_up(isp); - isp->otg.state = OTG_STATE_B_IDLE; - - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_SESS_VLD); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD); - dev_info(&isp->client.dev, "B-Peripheral sessions ok\n"); - dump_regs(isp, __FUNCTION__); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, so long - * as you don't plug a Mini-A cable into the jack. - */ - if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD) - b_peripheral(isp); - - return 0; - -#else - dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n"); - return -EINVAL; -#endif -} - - -/*-------------------------------------------------------------------------*/ - -static int -isp1301_set_power(struct otg_transceiver *dev, unsigned mA) -{ - if (!the_transceiver) - return -ENODEV; - if (dev->state == OTG_STATE_B_PERIPHERAL) - enable_vbus_draw(the_transceiver, mA); - return 0; -} - -static int -isp1301_start_srp(struct otg_transceiver *dev) -{ - struct isp1301 *isp = container_of(dev, struct isp1301, otg); - u32 otg_ctrl; - - if (!dev || isp != the_transceiver - || isp->otg.state != OTG_STATE_B_IDLE) - return -ENODEV; - - otg_ctrl = OTG_CTRL_REG; - if (!(otg_ctrl & OTG_BSESSEND)) - return -EINVAL; - - otg_ctrl |= OTG_B_BUSREQ; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; - OTG_CTRL_REG = otg_ctrl; - isp->otg.state = OTG_STATE_B_SRP_INIT; - - pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG); -#ifdef CONFIG_USB_OTG - check_state(isp, __FUNCTION__); -#endif - return 0; -} - -static int -isp1301_start_hnp(struct otg_transceiver *dev) -{ -#ifdef CONFIG_USB_OTG - struct isp1301 *isp = container_of(dev, struct isp1301, otg); - - if (!dev || isp != the_transceiver) - return -ENODEV; - if (isp->otg.default_a && (isp->otg.host == NULL - || !isp->otg.host->b_hnp_enable)) - return -ENOTCONN; - if (!isp->otg.default_a && (isp->otg.gadget == NULL - || !isp->otg.gadget->b_hnp_enable)) - return -ENOTCONN; - - /* We want hardware to manage most HNP protocol timings. - * So do this part as early as possible... - */ - switch (isp->otg.state) { - case OTG_STATE_B_HOST: - isp->otg.state = OTG_STATE_B_PERIPHERAL; - /* caller will suspend next */ - break; - case OTG_STATE_A_HOST: -#if 0 - /* autoconnect mode avoids irq latency bugs */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); -#endif - /* caller must suspend then clear A_BUSREQ */ - usb_gadget_vbus_connect(isp->otg.gadget); - OTG_CTRL_REG |= OTG_A_SETB_HNPEN; - - break; - case OTG_STATE_A_PERIPHERAL: - /* initiated by B-Host suspend */ - break; - default: - return -EILSEQ; - } - pr_debug("otg: HNP %s, %06x ...\n", - state_name(isp), OTG_CTRL_REG); - check_state(isp, __FUNCTION__); - return 0; -#else - /* srp-only */ - return -EINVAL; -#endif -} - -/*-------------------------------------------------------------------------*/ - -/* no error returns, they'd just make bus scanning stop */ -static int isp1301_probe(struct i2c_adapter *bus, int address, int kind) -{ - int status; - struct isp1301 *isp; - struct i2c_client *i2c; - - if (the_transceiver) - return 0; - - isp = kzalloc(sizeof *isp, GFP_KERNEL); - if (!isp) - return 0; - - INIT_WORK(&isp->work, isp1301_work, isp); - init_timer(&isp->timer); - isp->timer.function = isp1301_timer; - isp->timer.data = (unsigned long) isp; - - isp->irq = -1; - isp->client.addr = address; - i2c_set_clientdata(&isp->client, isp); - isp->client.adapter = bus; - isp->client.driver = &isp1301_driver; - strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE); - i2c = &isp->client; - - /* if this is a true probe, verify the chip ... */ - if (kind < 0) { - status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); - if (status != I2C_VENDOR_ID_PHILIPS) { - dev_dbg(&bus->dev, "addr %d not philips id: %d\n", - address, status); - goto fail1; - } - status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID); - if (status != I2C_PRODUCT_ID_PHILIPS_1301) { - dev_dbg(&bus->dev, "%d not isp1301, %d\n", - address, status); - goto fail1; - } - } - - status = i2c_attach_client(i2c); - if (status < 0) { - dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", - DRIVER_NAME, address, status); -fail1: - kfree(isp); - return 0; - } - isp->i2c_release = i2c->dev.release; - i2c->dev.release = isp1301_release; - - /* initial development used chiprev 2.00 */ - status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE); - dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n", - status >> 8, status & 0xff); - - /* make like power-on reset */ - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK); - - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI); - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - -#ifdef CONFIG_USB_OTG - status = otg_bind(isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't bind OTG\n"); - goto fail2; - } -#endif - - if (machine_is_omap_h2()) { - /* full speed signaling by default */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_SPEED_REG); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, - MC2_SPD_SUSP_CTRL); - - /* IRQ wired at M14 */ - omap_cfg_reg(M14_1510_GPIO2); - isp->irq = OMAP_GPIO_IRQ(2); - omap_request_gpio(2); - omap_set_gpio_direction(2, 1); - omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE); - } - - status = request_irq(isp->irq, isp1301_irq, - SA_SAMPLE_RANDOM, DRIVER_NAME, isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n", - isp->irq, status); -#ifdef CONFIG_USB_OTG -fail2: -#endif - i2c_detach_client(i2c); - goto fail1; - } - - isp->otg.dev = &isp->client.dev; - isp->otg.label = DRIVER_NAME; - - isp->otg.set_host = isp1301_set_host, - isp->otg.set_peripheral = isp1301_set_peripheral, - isp->otg.set_power = isp1301_set_power, - isp->otg.start_srp = isp1301_start_srp, - isp->otg.start_hnp = isp1301_start_hnp, - - enable_vbus_draw(isp, 0); - power_down(isp); - the_transceiver = isp; - -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); -#endif - - dump_regs(isp, __FUNCTION__); - -#ifdef VERBOSE - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); - dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); -#endif - - status = otg_set_transceiver(&isp->otg); - if (status < 0) - dev_err(&i2c->dev, "can't register transceiver, %d\n", - status); - - return 0; -} - -static int isp1301_scan_bus(struct i2c_adapter *bus) -{ - if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_READ_WORD_DATA)) - return -EINVAL; - return i2c_probe(bus, &addr_data, isp1301_probe); -} - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_omap", - }, - .id = 1301, /* FIXME "official", i2c-ids.h */ - .class = I2C_CLASS_HWMON, - .attach_adapter = isp1301_scan_bus, - .detach_client = isp1301_detach_client, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init isp_init(void) -{ - return i2c_add_driver(&isp1301_driver); -} -module_init(isp_init); - -static void __exit isp_exit(void) -{ - if (the_transceiver) - otg_set_transceiver(0); - i2c_del_driver(&isp1301_driver); -} -module_exit(isp_exit); - diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c deleted file mode 100644 index 2dc3d48375f..00000000000 --- a/drivers/i2c/chips/m41t00.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * drivers/i2c/chips/m41t00.c - * - * I2C client/driver for the ST M41T00 Real-Time Clock chip. - * - * Author: Mark A. 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 <asm/time.h> -#include <asm/rtc.h> - -#define M41T00_DRV_NAME "m41t00" - -static DECLARE_MUTEX(m41t00_mutex); - -static struct i2c_driver m41t00_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, -}; - -ulong -m41t00_get_rtc_time(void) -{ - s32 sec, min, hour, day, mon, year; - s32 sec1, min1, hour1, day1, mon1, year1; - ulong limit = 10; - - sec = min = hour = day = mon = year = 0; - sec1 = min1 = hour1 = day1 = mon1 = year1 = 0; - - down(&m41t00_mutex); - do { - if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0) - && ((min = i2c_smbus_read_byte_data(save_client, 1)) - >= 0) - && ((hour = i2c_smbus_read_byte_data(save_client, 2)) - >= 0) - && ((day = i2c_smbus_read_byte_data(save_client, 4)) - >= 0) - && ((mon = i2c_smbus_read_byte_data(save_client, 5)) - >= 0) - && ((year = i2c_smbus_read_byte_data(save_client, 6)) - >= 0) - && ((sec == sec1) && (min == min1) && (hour == hour1) - && (day == day1) && (mon == mon1) - && (year == year1))) - - break; - - sec1 = sec; - min1 = min; - hour1 = hour; - day1 = day; - mon1 = mon; - year1 = year; - } while (--limit > 0); - up(&m41t00_mutex); - - if (limit == 0) { - dev_warn(&save_client->dev, - "m41t00: can't read rtc chip\n"); - sec = min = hour = day = mon = year = 0; - } - - sec &= 0x7f; - min &= 0x7f; - hour &= 0x3f; - day &= 0x3f; - mon &= 0x1f; - year &= 0xff; - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - - year += 1900; - if (year < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); -} - -static void -m41t00_set_tlet(ulong arg) -{ - struct rtc_time tm; - ulong nowtime = *(ulong *)arg; - - to_tm(nowtime, &tm); - tm.tm_year = (tm.tm_year - 1900) % 100; - - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_year); - - down(&m41t00_mutex); - if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0) - || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x7f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x7f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x7f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0x7f) - < 0)) - - dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n"); - - up(&m41t00_mutex); - return; -} - -static ulong new_time; - -DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time); - -int -m41t00_set_rtc_time(ulong nowtime) -{ - new_time = nowtime; - - if (in_interrupt()) - tasklet_schedule(&m41t00_tasklet); - else - m41t00_set_tlet((ulong)&new_time); - - return 0; -} - -/* - ***************************************************************************** - * - * Driver Interface - * - ***************************************************************************** - */ -static int -m41t00_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, M41T00_DRV_NAME, I2C_NAME_SIZE); - client->addr = addr; - client->adapter = adap; - client->driver = &m41t00_driver; - - if ((rc = i2c_attach_client(client)) != 0) { - kfree(client); - return rc; - } - - save_client = client; - return 0; -} - -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); - tasklet_kill(&m41t00_tasklet); - } - 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) -{ - return i2c_add_driver(&m41t00_driver); -} - -static void __exit -m41t00_exit(void) -{ - i2c_del_driver(&m41t00_driver); - return; -} - -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"); diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c deleted file mode 100644 index 6d3ff584155..00000000000 --- a/drivers/i2c/chips/max6875.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - 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 <asm/semaphore.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 semaphore 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; - - down(&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: - up(&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); - init_MUTEX(&data->update_lock); - - /* Init fake client data */ - /* set the client data to the i2c_client so that it will get freed */ - i2c_set_clientdata(fake_client, fake_client); - 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_detach; - - sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr); - - return 0; - -exit_detach: - i2c_detach_client(real_client); -exit_kfree2: - kfree(fake_client); -exit_kfree1: - kfree(data); - return err; -} - -static int max6875_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 __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); diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c deleted file mode 100644 index 54b6e6a4bee..00000000000 --- a/drivers/i2c/chips/pca9539.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - 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; - - /* 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 (don't care about failure) */ - sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group); - - return 0; - -exit_kfree: - kfree(data); -exit: - return err; -} - -static int pca9539_detach_client(struct i2c_client *client) -{ - int err; - - 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); - diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c deleted file mode 100644 index c3e6449c448..00000000000 --- a/drivers/i2c/chips/pcf8574.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - 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); - -/* - * 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 */ - 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 = 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); diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c deleted file mode 100644 index 36cff09c678..00000000000 --- a/drivers/i2c/chips/pcf8591.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - 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> - -/* 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 semaphore 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); - - down(&data->update_lock); - if (val) - data->control |= PCF8591_CONTROL_AOEF; - else - data->control &= ~PCF8591_CONTROL_AOEF; - i2c_smbus_write_byte(client, data->control); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, - show_out0_enable, set_out0_enable); - -/* - * 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); - init_MUTEX(&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 */ - device_create_file(&new_client->dev, &dev_attr_out0_enable); - device_create_file(&new_client->dev, &dev_attr_out0_output); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - - /* Register input2 if not in "two differential inputs" mode */ - if (input_mode != 3 ) - device_create_file(&new_client->dev, &dev_attr_in2_input); - - /* Register input3 only in "four single ended inputs" mode */ - if (input_mode == 0) - device_create_file(&new_client->dev, &dev_attr_in3_input); - - return 0; - - /* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -exit_kfree: - kfree(data); -exit: - return err; -} - -static int pcf8591_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 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); - - down(&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); - - up(&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); diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c deleted file mode 100644 index ceaa6b0bdfd..00000000000 --- a/drivers/i2c/chips/rtc8564.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * linux/drivers/i2c/chips/rtc8564.c - * - * Copyright (C) 2002-2004 Stefan Eletzhofer - * - * based on linux/drivers/acron/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 system3's EPSON RTC 8564 chip - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/bcd.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/rtc.h> /* get the user-level API */ -#include <linux/init.h> - -#include "rtc8564.h" - -#ifdef DEBUG -# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0); -#else -# define _DBG(x, fmt, args...) do { } while(0); -#endif - -#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \ - "mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \ - (rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \ - (rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl); - -struct rtc8564_data { - struct i2c_client client; - u16 ctrl; -}; - -static inline u8 _rtc8564_ctrl1(struct i2c_client *client) -{ - struct rtc8564_data *data = i2c_get_clientdata(client); - return data->ctrl & 0xff; -} -static inline u8 _rtc8564_ctrl2(struct i2c_client *client) -{ - struct rtc8564_data *data = i2c_get_clientdata(client); - return (data->ctrl & 0xff00) >> 8; -} - -#define CTRL1(c) _rtc8564_ctrl1(c) -#define CTRL2(c) _rtc8564_ctrl2(c) - -static int debug;; -module_param(debug, int, S_IRUGO | S_IWUSR); - -static struct i2c_driver rtc8564_driver; - -static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_addr, - .probe = ignore, - .ignore = ignore, -}; - -static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem); -static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem); - -static int rtc8564_read(struct i2c_client *client, unsigned char adr, - unsigned char *buf, unsigned char len) -{ - int ret = -EIO; - unsigned char addr[1] = { adr }; - struct i2c_msg msgs[2] = { - {client->addr, 0, 1, addr}, - {client->addr, I2C_M_RD, len, buf} - }; - - _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len); - - if (!buf) { - ret = -EINVAL; - goto done; - } - - ret = i2c_transfer(client->adapter, msgs, 2); - if (ret == 2) { - ret = 0; - } - -done: - return ret; -} - -static int rtc8564_write(struct i2c_client *client, unsigned char adr, - unsigned char *data, unsigned char len) -{ - int ret = 0; - unsigned char _data[16]; - struct i2c_msg wr; - int i; - - if (!data || len > 15) { - ret = -EINVAL; - goto done; - } - - _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len); - - _data[0] = adr; - for (i = 0; i < len; i++) { - _data[i + 1] = data[i]; - _DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]); - } - - wr.addr = client->addr; - wr.flags = 0; - wr.len = len + 1; - wr.buf = _data; - - ret = i2c_transfer(client->adapter, &wr, 1); - if (ret == 1) { - ret = 0; - } - -done: - return ret; -} - -static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind) -{ - int ret; - struct i2c_client *new_client; - struct rtc8564_data *d; - unsigned char data[10]; - unsigned char ad[1] = { 0 }; - struct i2c_msg ctrl_wr[1] = { - {addr, 0, 2, data} - }; - struct i2c_msg ctrl_rd[2] = { - {addr, 0, 1, ad}, - {addr, I2C_M_RD, 2, data} - }; - - d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL); - if (!d) { - ret = -ENOMEM; - goto done; - } - new_client = &d->client; - - strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); - i2c_set_clientdata(new_client, d); - new_client->addr = addr; - new_client->adapter = adap; - new_client->driver = &rtc8564_driver; - - _DBG(1, "client=%p", new_client); - - /* init ctrl1 reg */ - data[0] = 0; - data[1] = 0; - ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); - if (ret != 1) { - printk(KERN_INFO "rtc8564: cant init ctrl1\n"); - ret = -ENODEV; - goto done; - } - - /* read back ctrl1 and ctrl2 */ - ret = i2c_transfer(new_client->adapter, ctrl_rd, 2); - if (ret != 2) { - printk(KERN_INFO "rtc8564: cant read ctrl\n"); - ret = -ENODEV; - goto done; - } - - d->ctrl = data[0] | (data[1] << 8); - - _DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x", - data[0], data[1]); - - ret = i2c_attach_client(new_client); -done: - if (ret) { - kfree(d); - } - return ret; -} - -static int rtc8564_probe(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, rtc8564_attach); -} - -static int rtc8564_detach(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - -static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt) -{ - int ret = -EIO; - unsigned char buf[15]; - - _DBG(1, "client=%p, dt=%p", client, dt); - - if (!dt) - return -EINVAL; - - memset(buf, 0, sizeof(buf)); - - ret = rtc8564_read(client, 0, buf, 15); - if (ret) - return ret; - - /* century stored in minute alarm reg */ - dt->year = BCD2BIN(buf[RTC8564_REG_YEAR]); - dt->year += 100 * BCD2BIN(buf[RTC8564_REG_AL_MIN] & 0x3f); - dt->mday = BCD2BIN(buf[RTC8564_REG_DAY] & 0x3f); - dt->wday = BCD2BIN(buf[RTC8564_REG_WDAY] & 7); - dt->mon = BCD2BIN(buf[RTC8564_REG_MON_CENT] & 0x1f); - - dt->secs = BCD2BIN(buf[RTC8564_REG_SEC] & 0x7f); - dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80; - dt->mins = BCD2BIN(buf[RTC8564_REG_MIN] & 0x7f); - dt->hours = BCD2BIN(buf[RTC8564_REG_HR] & 0x3f); - - _DBGRTCTM(2, *dt); - - return 0; -} - -static int -rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) -{ - int ret, len = 5; - unsigned char buf[15]; - - _DBG(1, "client=%p, dt=%p", client, dt); - - if (!dt) - return -EINVAL; - - _DBGRTCTM(2, *dt); - - buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP; - buf[RTC8564_REG_CTRL2] = CTRL2(client); - buf[RTC8564_REG_SEC] = BIN2BCD(dt->secs); - buf[RTC8564_REG_MIN] = BIN2BCD(dt->mins); - buf[RTC8564_REG_HR] = BIN2BCD(dt->hours); - - if (datetoo) { - len += 5; - buf[RTC8564_REG_DAY] = BIN2BCD(dt->mday); - buf[RTC8564_REG_WDAY] = BIN2BCD(dt->wday); - buf[RTC8564_REG_MON_CENT] = BIN2BCD(dt->mon) & 0x1f; - /* century stored in minute alarm reg */ - buf[RTC8564_REG_YEAR] = BIN2BCD(dt->year % 100); - buf[RTC8564_REG_AL_MIN] = BIN2BCD(dt->year / 100); - } - - ret = rtc8564_write(client, 0, buf, len); - if (ret) { - _DBG(1, "error writing data! %d", ret); - } - - buf[RTC8564_REG_CTRL1] = CTRL1(client); - ret = rtc8564_write(client, 0, buf, 1); - if (ret) { - _DBG(1, "error writing data! %d", ret); - } - - return ret; -} - -static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl) -{ - struct rtc8564_data *data = i2c_get_clientdata(client); - - if (!ctrl) - return -1; - - *ctrl = data->ctrl; - return 0; -} - -static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl) -{ - struct rtc8564_data *data = i2c_get_clientdata(client); - unsigned char buf[2]; - - if (!ctrl) - return -1; - - buf[0] = *ctrl & 0xff; - buf[1] = (*ctrl & 0xff00) >> 8; - data->ctrl = *ctrl; - - return rtc8564_write(client, 0, buf, 2); -} - -static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem) -{ - - if (!mem) - return -EINVAL; - - return rtc8564_read(client, mem->loc, mem->data, mem->nr); -} - -static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem) -{ - - if (!mem) - return -EINVAL; - - return rtc8564_write(client, mem->loc, mem->data, mem->nr); -} - -static int -rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - - _DBG(1, "cmd=%d", cmd); - - switch (cmd) { - case RTC_GETDATETIME: - return rtc8564_get_datetime(client, arg); - - case RTC_SETTIME: - return rtc8564_set_datetime(client, arg, 0); - - case RTC_SETDATETIME: - return rtc8564_set_datetime(client, arg, 1); - - case RTC_GETCTRL: - return rtc8564_get_ctrl(client, arg); - - case RTC_SETCTRL: - return rtc8564_set_ctrl(client, arg); - - case MEM_READ: - return rtc8564_read_mem(client, arg); - - case MEM_WRITE: - return rtc8564_write_mem(client, arg); - - default: - return -EINVAL; - } -} - -static struct i2c_driver rtc8564_driver = { - .driver = { - .name = "RTC8564", - }, - .id = I2C_DRIVERID_RTC8564, - .attach_adapter = rtc8564_probe, - .detach_client = rtc8564_detach, - .command = rtc8564_command -}; - -static __init int rtc8564_init(void) -{ - return i2c_add_driver(&rtc8564_driver); -} - -static __exit void rtc8564_exit(void) -{ - i2c_del_driver(&rtc8564_driver); -} - -MODULE_AUTHOR("Stefan Eletzhofer <Stefan.Eletzhofer@eletztrick.de>"); -MODULE_DESCRIPTION("EPSON RTC8564 Driver"); -MODULE_LICENSE("GPL"); - -module_init(rtc8564_init); -module_exit(rtc8564_exit); diff --git a/drivers/i2c/chips/rtc8564.h b/drivers/i2c/chips/rtc8564.h deleted file mode 100644 index e5342d10b8f..00000000000 --- a/drivers/i2c/chips/rtc8564.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * linux/drivers/i2c/chips/rtc8564.h - * - * Copyright (C) 2002-2004 Stefan Eletzhofer - * - * based on linux/drivers/acron/char/pcf8583.h - * 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. - */ -struct rtc_tm { - unsigned char secs; - unsigned char mins; - unsigned char hours; - unsigned char mday; - unsigned char mon; - unsigned short year; /* xxxx 4 digits :) */ - unsigned char wday; - unsigned char vl; -}; - -struct mem { - unsigned int loc; - unsigned int nr; - unsigned char *data; -}; - -#define RTC_GETDATETIME 0 -#define RTC_SETTIME 1 -#define RTC_SETDATETIME 2 -#define RTC_GETCTRL 3 -#define RTC_SETCTRL 4 -#define MEM_READ 5 -#define MEM_WRITE 6 - -#define RTC8564_REG_CTRL1 0x0 /* T 0 S 0 | T 0 0 0 */ -#define RTC8564_REG_CTRL2 0x1 /* 0 0 0 TI/TP | AF TF AIE TIE */ -#define RTC8564_REG_SEC 0x2 /* VL 4 2 1 | 8 4 2 1 */ -#define RTC8564_REG_MIN 0x3 /* x 4 2 1 | 8 4 2 1 */ -#define RTC8564_REG_HR 0x4 /* x x 2 1 | 8 4 2 1 */ -#define RTC8564_REG_DAY 0x5 /* x x 2 1 | 8 4 2 1 */ -#define RTC8564_REG_WDAY 0x6 /* x x x x | x 4 2 1 */ -#define RTC8564_REG_MON_CENT 0x7 /* C x x 1 | 8 4 2 1 */ -#define RTC8564_REG_YEAR 0x8 /* 8 4 2 1 | 8 4 2 1 */ -#define RTC8564_REG_AL_MIN 0x9 /* AE 4 2 1 | 8 4 2 1 */ -#define RTC8564_REG_AL_HR 0xa /* AE 4 2 1 | 8 4 2 1 */ -#define RTC8564_REG_AL_DAY 0xb /* AE x 2 1 | 8 4 2 1 */ -#define RTC8564_REG_AL_WDAY 0xc /* AE x x x | x 4 2 1 */ -#define RTC8564_REG_CLKOUT 0xd /* FE x x x | x x FD1 FD0 */ -#define RTC8564_REG_TCTL 0xe /* TE x x x | x x FD1 FD0 */ -#define RTC8564_REG_TIMER 0xf /* 8 bit binary */ - -/* Control reg */ -#define RTC8564_CTRL1_TEST1 (1<<3) -#define RTC8564_CTRL1_STOP (1<<5) -#define RTC8564_CTRL1_TEST2 (1<<7) - -#define RTC8564_CTRL2_TIE (1<<0) -#define RTC8564_CTRL2_AIE (1<<1) -#define RTC8564_CTRL2_TF (1<<2) -#define RTC8564_CTRL2_AF (1<<3) -#define RTC8564_CTRL2_TI_TP (1<<4) - -/* CLKOUT frequencies */ -#define RTC8564_FD_32768HZ (0x0) -#define RTC8564_FD_1024HZ (0x1) -#define RTC8564_FD_32 (0x2) -#define RTC8564_FD_1HZ (0x3) - -/* Timer CTRL */ -#define RTC8564_TD_4096HZ (0x0) -#define RTC8564_TD_64HZ (0x1) -#define RTC8564_TD_1HZ (0x2) -#define RTC8564_TD_1_60HZ (0x3) - -#define I2C_DRIVERID_RTC8564 0xf000 diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c deleted file mode 100644 index 1af3dfbb808..00000000000 --- a/drivers/i2c/chips/tps65010.c +++ /dev/null @@ -1,1069 +0,0 @@ -/* - * tps65010 - driver for tps6501x power management chips - * - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2004-2005 David Brownell - * - * 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/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/workqueue.h> -#include <linux/suspend.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -#include <asm/irq.h> -#include <asm/mach-types.h> - -#include <asm/arch/gpio.h> -#include <asm/arch/mux.h> -#include <asm/arch/tps65010.h> - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_VERSION "2 May 2005" -#define DRIVER_NAME (tps65010_driver.name) - -MODULE_DESCRIPTION("TPS6501x Power Management Driver"); -MODULE_LICENSE("GPL"); - -static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - -static struct i2c_driver tps65010_driver; - -/*-------------------------------------------------------------------------*/ - -/* This driver handles a family of multipurpose chips, which incorporate - * voltage regulators, lithium ion/polymer battery charging, GPIOs, LEDs, - * and other features often needed in portable devices like cell phones - * or digital cameras. - * - * The tps65011 and tps65013 have different voltage settings compared - * to tps65010 and tps65012. The tps65013 has a NO_CHG status/irq. - * All except tps65010 have "wait" mode, possibly defaulted so that - * battery-insert != device-on. - * - * We could distinguish between some models by checking VDCDC1.UVLO or - * other registers, unless they've been changed already after powerup - * as part of board setup by a bootloader. - */ -enum tps_model { - TPS_UNKNOWN = 0, - TPS65010, - TPS65011, - TPS65012, - TPS65013, -}; - -struct tps65010 { - struct i2c_client client; - struct semaphore lock; - int irq; - struct work_struct work; - struct dentry *file; - unsigned charging:1; - unsigned por:1; - unsigned model:8; - u16 vbus; - unsigned long flags; -#define FLAG_VBUS_CHANGED 0 -#define FLAG_IRQ_ENABLE 1 - - /* copies of last register state */ - u8 chgstatus, regstatus, chgconf; - u8 nmask1, nmask2; - - /* not currently tracking GPIO state */ -}; - -#define POWER_POLL_DELAY msecs_to_jiffies(800) - -/*-------------------------------------------------------------------------*/ - -#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) - -static void dbg_chgstat(char *buf, size_t len, u8 chgstatus) -{ - snprintf(buf, len, "%02x%s%s%s%s%s%s%s%s\n", - chgstatus, - (chgstatus & TPS_CHG_USB) ? " USB" : "", - (chgstatus & TPS_CHG_AC) ? " AC" : "", - (chgstatus & TPS_CHG_THERM) ? " therm" : "", - (chgstatus & TPS_CHG_TERM) ? " done" : - ((chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) - ? " (charging)" : ""), - (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "", - (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "", - (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "", - (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : ""); -} - -static void dbg_regstat(char *buf, size_t len, u8 regstatus) -{ - snprintf(buf, len, "%02x %s%s%s%s%s%s%s%s\n", - regstatus, - (regstatus & TPS_REG_ONOFF) ? "off" : "(on)", - (regstatus & TPS_REG_COVER) ? " uncover" : "", - (regstatus & TPS_REG_UVLO) ? " UVLO" : "", - (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", - (regstatus & TPS_REG_PG_LD02) ? " ld02_bad" : "", - (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", - (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", - (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); -} - -static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) -{ - const char *hibit; - - if (por) - hibit = (chgconfig & TPS_CHARGE_POR) - ? "POR=69ms" : "POR=1sec"; - else - hibit = (chgconfig & TPS65013_AUA) ? "AUA" : ""; - - snprintf(buf, len, "%02x %s%s%s AC=%d%% USB=%dmA %sCharge\n", - chgconfig, hibit, - (chgconfig & TPS_CHARGE_RESET) ? " reset" : "", - (chgconfig & TPS_CHARGE_FAST) ? " fast" : "", - ({int p; switch ((chgconfig >> 3) & 3) { - case 3: p = 100; break; - case 2: p = 75; break; - case 1: p = 50; break; - default: p = 25; break; - }; p; }), - (chgconfig & TPS_VBUS_CHARGING) - ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100) - : 0, - (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No"); -} - -#endif - -#ifdef DEBUG - -static void show_chgstatus(const char *label, u8 chgstatus) -{ - char buf [100]; - - dbg_chgstat(buf, sizeof buf, chgstatus); - pr_debug("%s: %s %s", DRIVER_NAME, label, buf); -} - -static void show_regstatus(const char *label, u8 regstatus) -{ - char buf [100]; - - dbg_regstat(buf, sizeof buf, regstatus); - pr_debug("%s: %s %s", DRIVER_NAME, label, buf); -} - -static void show_chgconfig(int por, const char *label, u8 chgconfig) -{ - char buf [100]; - - dbg_chgconf(por, buf, sizeof buf, chgconfig); - pr_debug("%s: %s %s", DRIVER_NAME, label, buf); -} - -#else - -static inline void show_chgstatus(const char *label, u8 chgstatus) { } -static inline void show_regstatus(const char *label, u8 chgstatus) { } -static inline void show_chgconfig(int por, const char *label, u8 chgconfig) { } - -#endif - -#ifdef CONFIG_DEBUG_FS - -static int dbg_show(struct seq_file *s, void *_) -{ - struct tps65010 *tps = s->private; - u8 value, v2; - unsigned i; - char buf[100]; - const char *chip; - - switch (tps->model) { - case TPS65010: chip = "tps65010"; break; - case TPS65011: chip = "tps65011"; break; - case TPS65012: chip = "tps65012"; break; - case TPS65013: chip = "tps65013"; break; - default: chip = NULL; break; - } - seq_printf(s, "driver %s\nversion %s\nchip %s\n\n", - DRIVER_NAME, DRIVER_VERSION, chip); - - down(&tps->lock); - - /* FIXME how can we tell whether a battery is present? - * likely involves a charge gauging chip (like BQ26501). - */ - - seq_printf(s, "%scharging\n\n", tps->charging ? "" : "(not) "); - - - /* registers for monitoring battery charging and status; note - * that reading chgstat and regstat may ack IRQs... - */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); - dbg_chgconf(tps->por, buf, sizeof buf, value); - seq_printf(s, "chgconfig %s", buf); - - value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); - dbg_chgstat(buf, sizeof buf, value); - seq_printf(s, "chgstat %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1); - dbg_chgstat(buf, sizeof buf, value); - seq_printf(s, "mask1 %s", buf); - /* ignore ackint1 */ - - value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); - dbg_regstat(buf, sizeof buf, value); - seq_printf(s, "regstat %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2); - dbg_regstat(buf, sizeof buf, value); - seq_printf(s, "mask2 %s\n", buf); - /* ignore ackint2 */ - - (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); - - - /* VMAIN voltage, enable lowpower, etc */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1); - seq_printf(s, "vdcdc1 %02x\n", value); - - /* VCORE voltage, vibrator on/off */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2); - seq_printf(s, "vdcdc2 %02x\n", value); - - /* both LD0s, and their lowpower behavior */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1); - seq_printf(s, "vregs1 %02x\n\n", value); - - - /* LEDs and GPIOs */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER); - seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", - (value & 0x80) - ? ((v2 & 0x80) ? "on" : "off") - : ((v2 & 0x80) ? "blink" : "(nPG)"), - value, v2, - (value & 0x7f) * 10, (v2 & 0x7f) * 100); - - value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER); - seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", - (value & 0x80) - ? ((v2 & 0x80) ? "on" : "off") - : ((v2 & 0x80) ? "blink" : "off"), - value, v2, - (value & 0x7f) * 10, (v2 & 0x7f) * 100); - - value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3); - seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); - - for (i = 0; i < 4; i++) { - if (value & (1 << (4 + i))) - seq_printf(s, " gpio%d-out %s\n", i + 1, - (value & (1 << i)) ? "low" : "hi "); - else - seq_printf(s, " gpio%d-in %s %s %s\n", i + 1, - (value & (1 << i)) ? "hi " : "low", - (v2 & (1 << i)) ? "no-irq" : "irq", - (v2 & (1 << (4 + i))) ? "rising" : "falling"); - } - - up(&tps->lock); - return 0; -} - -static int dbg_tps_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_show, inode->u.generic_ip); -} - -static struct file_operations debug_fops = { - .open = dbg_tps_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#define DEBUG_FOPS &debug_fops - -#else -#define DEBUG_FOPS NULL -#endif - -/*-------------------------------------------------------------------------*/ - -/* handle IRQS in a task context, so we can use I2C calls */ -static void tps65010_interrupt(struct tps65010 *tps) -{ - u8 tmp = 0, mask, poll; - - /* IRQs won't trigger irqs for certain events, but we can get - * others by polling (normally, with external power applied). - */ - poll = 0; - - /* regstatus irqs */ - if (tps->nmask2) { - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); - mask = tmp ^ tps->regstatus; - tps->regstatus = tmp; - mask &= tps->nmask2; - } else - mask = 0; - if (mask) { - tps->regstatus = tmp; - /* may need to shut something down ... */ - - /* "off" usually means deep sleep */ - if (tmp & TPS_REG_ONOFF) { - pr_info("%s: power off button\n", DRIVER_NAME); -#if 0 - /* REVISIT: this might need its own workqueue - * plus tweaks including deadlock avoidance ... - */ - software_suspend(); -#endif - poll = 1; - } - } - - /* chgstatus irqs */ - if (tps->nmask1) { - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); - mask = tmp ^ tps->chgstatus; - tps->chgstatus = tmp; - mask &= tps->nmask1; - } else - mask = 0; - if (mask) { - unsigned charging = 0; - - show_chgstatus("chg/irq", tmp); - if (tmp & (TPS_CHG_USB|TPS_CHG_AC)) - show_chgconfig(tps->por, "conf", tps->chgconf); - - /* Unless it was turned off or disabled, we charge any - * battery whenever there's power available for it - * and the charger hasn't been disabled. - */ - if (!(tps->chgstatus & ~(TPS_CHG_USB|TPS_CHG_AC)) - && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) - && (tps->chgconf & TPS_CHARGE_ENABLE) - ) { - if (tps->chgstatus & TPS_CHG_USB) { - /* VBUS options are readonly until reconnect */ - if (mask & TPS_CHG_USB) - set_bit(FLAG_VBUS_CHANGED, &tps->flags); - charging = 1; - } else if (tps->chgstatus & TPS_CHG_AC) - charging = 1; - } - if (charging != tps->charging) { - tps->charging = charging; - pr_info("%s: battery %scharging\n", - DRIVER_NAME, charging ? "" : - ((tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) - ? "NOT " : "dis")); - } - } - - /* always poll to detect (a) power removal, without tps65013 - * NO_CHG IRQ; or (b) restart of charging after stop. - */ - if ((tps->model != TPS65013 || !tps->charging) - && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) - poll = 1; - if (poll) - (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); - - /* also potentially gpio-in rise or fall */ -} - -/* handle IRQs and polling using keventd for now */ -static void tps65010_work(void *_tps) -{ - struct tps65010 *tps = _tps; - - down(&tps->lock); - - tps65010_interrupt(tps); - - if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { - int status; - u8 chgconfig, tmp; - - chgconfig = i2c_smbus_read_byte_data(&tps->client, - TPS_CHGCONFIG); - chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); - if (tps->vbus == 500) - chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING; - else if (tps->vbus >= 100) - chgconfig |= TPS_VBUS_CHARGING; - - status = i2c_smbus_write_byte_data(&tps->client, - TPS_CHGCONFIG, chgconfig); - - /* vbus update fails unless VBUS is connected! */ - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); - tps->chgconf = tmp; - show_chgconfig(tps->por, "update vbus", tmp); - } - - if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) - enable_irq(tps->irq); - - up(&tps->lock); -} - -static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) -{ - struct tps65010 *tps = _tps; - - disable_irq_nosync(irq); - set_bit(FLAG_IRQ_ENABLE, &tps->flags); - (void) schedule_work(&tps->work); - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -static struct tps65010 *the_tps; - -static int __exit tps65010_detach_client(struct i2c_client *client) -{ - struct tps65010 *tps; - - tps = container_of(client, struct tps65010, client); -#ifdef CONFIG_ARM - if (machine_is_omap_h2()) - omap_free_gpio(58); - if (machine_is_omap_osk()) - omap_free_gpio(OMAP_MPUIO(1)); -#endif - free_irq(tps->irq, tps); - debugfs_remove(tps->file); - if (i2c_detach_client(client) == 0) - kfree(tps); - the_tps = NULL; - return 0; -} - -static int tps65010_noscan(struct i2c_adapter *bus) -{ - /* pure paranoia, in case someone adds another i2c bus - * after our init section's gone... - */ - return -ENODEV; -} - -/* no error returns, they'd just make bus scanning stop */ -static int __init -tps65010_probe(struct i2c_adapter *bus, int address, int kind) -{ - struct tps65010 *tps; - int status; - unsigned long irqflags; - - if (the_tps) { - dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); - return 0; - } - - tps = kzalloc(sizeof *tps, GFP_KERNEL); - if (!tps) - return 0; - - init_MUTEX(&tps->lock); - INIT_WORK(&tps->work, tps65010_work, tps); - tps->irq = -1; - tps->client.addr = address; - tps->client.adapter = bus; - tps->client.driver = &tps65010_driver; - strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); - - status = i2c_attach_client(&tps->client); - if (status < 0) { - dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", - DRIVER_NAME, address, status); - goto fail1; - } - -#ifdef CONFIG_ARM - irqflags = SA_SAMPLE_RANDOM | SA_TRIGGER_LOW; - if (machine_is_omap_h2()) { - tps->model = TPS65010; - omap_cfg_reg(W4_GPIO58); - tps->irq = OMAP_GPIO_IRQ(58); - omap_request_gpio(58); - omap_set_gpio_direction(58, 1); - irqflags |= SA_TRIGGER_FALLING; - } - if (machine_is_omap_osk()) { - tps->model = TPS65010; - // omap_cfg_reg(U19_1610_MPUIO1); - tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); - omap_request_gpio(OMAP_MPUIO(1)); - omap_set_gpio_direction(OMAP_MPUIO(1), 1); - irqflags |= SA_TRIGGER_FALLING; - } - if (machine_is_omap_h3()) { - tps->model = TPS65013; - - // FIXME set up this board's IRQ ... - } -#else - irqflags = SA_SAMPLE_RANDOM; -#endif - - if (tps->irq > 0) { - status = request_irq(tps->irq, tps65010_irq, - irqflags, DRIVER_NAME, tps); - if (status < 0) { - dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", - tps->irq, status); - i2c_detach_client(&tps->client); - goto fail1; - } -#ifdef CONFIG_ARM - /* annoying race here, ideally we'd have an option - * to claim the irq now and enable it later. - */ - disable_irq(tps->irq); - set_bit(FLAG_IRQ_ENABLE, &tps->flags); -#endif - } else - printk(KERN_WARNING "%s: IRQ not configured!\n", - DRIVER_NAME); - - - switch (tps->model) { - case TPS65010: - case TPS65012: - tps->por = 1; - break; - case TPS_UNKNOWN: - printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); - break; - /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ - } - tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); - show_chgconfig(tps->por, "conf/init", tps->chgconf); - - show_chgstatus("chg/init", - i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS)); - show_regstatus("reg/init", - i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS)); - - pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), - i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), - i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); - pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), - i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); - - tps65010_driver.attach_adapter = tps65010_noscan; - the_tps = tps; - -#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) - /* USB hosts can't draw VBUS. OTG devices could, later - * when OTG infrastructure enables it. USB peripherals - * could be relying on VBUS while booting, though. - */ - tps->vbus = 100; -#endif - - /* unmask the "interesting" irqs, then poll once to - * kickstart monitoring, initialize shadowed status - * registers, and maybe disable VBUS draw. - */ - tps->nmask1 = ~0; - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); - - tps->nmask2 = TPS_REG_ONOFF; - if (tps->model == TPS65013) - tps->nmask2 |= TPS_REG_NO_CHG; - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); - - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f - | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); - - tps65010_work(tps); - - tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, - tps, DEBUG_FOPS); - return 0; -fail1: - kfree(tps); - return 0; -} - -static int __init tps65010_scan_bus(struct i2c_adapter *bus) -{ - if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; - return i2c_probe(bus, &addr_data, tps65010_probe); -} - -static struct i2c_driver tps65010_driver = { - .driver = { - .name = "tps65010", - }, - .attach_adapter = tps65010_scan_bus, - .detach_client = __exit_p(tps65010_detach_client), -}; - -/*-------------------------------------------------------------------------*/ - -/* Draw from VBUS: - * 0 mA -- DON'T DRAW (might supply power instead) - * 100 mA -- usb unit load (slowest charge rate) - * 500 mA -- usb high power (fast battery charge) - */ -int tps65010_set_vbus_draw(unsigned mA) -{ - unsigned long flags; - - if (!the_tps) - return -ENODEV; - - /* assumes non-SMP */ - local_irq_save(flags); - if (mA >= 500) - mA = 500; - else if (mA >= 100) - mA = 100; - else - mA = 0; - the_tps->vbus = mA; - if ((the_tps->chgstatus & TPS_CHG_USB) - && test_and_set_bit( - FLAG_VBUS_CHANGED, &the_tps->flags)) { - /* gadget drivers call this in_irq() */ - (void) schedule_work(&the_tps->work); - } - local_irq_restore(flags); - - return 0; -} -EXPORT_SYMBOL(tps65010_set_vbus_draw); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_gpio_out_value parameter: - * gpio: GPIO1, GPIO2, GPIO3 or GPIO4 - * value: LOW or HIGH - */ -int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) -{ - int status; - unsigned defgpio; - - if (!the_tps) - return -ENODEV; - if ((gpio < GPIO1) || (gpio > GPIO4)) - return -EINVAL; - - down(&the_tps->lock); - - defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); - - /* Configure GPIO for output */ - defgpio |= 1 << (gpio + 3); - - /* Writing 1 forces a logic 0 on that GPIO and vice versa */ - switch (value) { - case LOW: - defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */ - break; - /* case HIGH: */ - default: - defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */ - break; - } - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_DEFGPIO, defgpio); - - pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, - gpio, value ? "high" : "low", - i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); - - up(&the_tps->lock); - return status; -} -EXPORT_SYMBOL(tps65010_set_gpio_out_value); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_led parameter: - * led: LED1 or LED2 - * mode: ON, OFF or BLINK - */ -int tps65010_set_led(unsigned led, unsigned mode) -{ - int status; - unsigned led_on, led_per, offs; - - if (!the_tps) - return -ENODEV; - - if (led == LED1) - offs = 0; - else { - offs = 2; - led = LED2; - } - - down(&the_tps->lock); - - pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, - TPS_LED1_ON + offs)); - - pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, - TPS_LED1_PER + offs)); - - switch (mode) { - case OFF: - led_on = 1 << 7; - led_per = 0 << 7; - break; - case ON: - led_on = 1 << 7; - led_per = 1 << 7; - break; - case BLINK: - led_on = 0x30 | (0 << 7); - led_per = 0x08 | (1 << 7); - break; - default: - printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n", - DRIVER_NAME); - up(&the_tps->lock); - return -EINVAL; - } - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_LED1_ON + offs, led_on); - - if (status != 0) { - printk(KERN_ERR "%s: Failed to write led%i_on register\n", - DRIVER_NAME, led); - up(&the_tps->lock); - return status; - } - - pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_LED1_PER + offs, led_per); - - if (status != 0) { - printk(KERN_ERR "%s: Failed to write led%i_per register\n", - DRIVER_NAME, led); - up(&the_tps->lock); - return status; - } - - pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, - TPS_LED1_PER + offs)); - - up(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65010_set_led); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_vib parameter: - * value: ON or OFF - */ -int tps65010_set_vib(unsigned value) -{ - int status; - unsigned vdcdc2; - - if (!the_tps) - return -ENODEV; - - down(&the_tps->lock); - - vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); - vdcdc2 &= ~(1 << 1); - if (value) - vdcdc2 |= (1 << 1); - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_VDCDC2, vdcdc2); - - pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); - - up(&the_tps->lock); - return status; -} -EXPORT_SYMBOL(tps65010_set_vib); - -/*-------------------------------------------------------------------------*/ -/* tps65010_set_low_pwr parameter: - * mode: ON or OFF - */ -int tps65010_set_low_pwr(unsigned mode) -{ - int status; - unsigned vdcdc1; - - if (!the_tps) - return -ENODEV; - - down(&the_tps->lock); - - pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, - mode ? "enable" : "disable", - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); - - vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); - - switch (mode) { - case OFF: - vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ - break; - /* case ON: */ - default: - vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ - break; - } - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_VDCDC1, vdcdc1); - - if (status != 0) - printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", - DRIVER_NAME); - else - pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); - - up(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65010_set_low_pwr); - -/*-------------------------------------------------------------------------*/ -/* tps65010_config_vregs1 parameter: - * value to be written to VREGS1 register - * Note: The complete register is written, set all bits you need - */ -int tps65010_config_vregs1(unsigned value) -{ - int status; - - if (!the_tps) - return -ENODEV; - - down(&the_tps->lock); - - pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_VREGS1, value); - - if (status != 0) - printk(KERN_ERR "%s: Failed to write vregs1 register\n", - DRIVER_NAME); - else - pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); - - up(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65010_config_vregs1); - -/*-------------------------------------------------------------------------*/ -/* tps65013_set_low_pwr parameter: - * mode: ON or OFF - */ - -/* FIXME: Assumes AC or USB power is present. Setting AUA bit is not - required if power supply is through a battery */ - -int tps65013_set_low_pwr(unsigned mode) -{ - int status; - unsigned vdcdc1, chgconfig; - - if (!the_tps || the_tps->por) - return -ENODEV; - - down(&the_tps->lock); - - pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", - DRIVER_NAME, - mode ? "enable" : "disable", - i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); - - chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); - vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); - - switch (mode) { - case OFF: - chgconfig &= ~TPS65013_AUA; /* disable AUA bit */ - vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ - break; - /* case ON: */ - default: - chgconfig |= TPS65013_AUA; /* enable AUA bit */ - vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ - break; - } - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_CHGCONFIG, chgconfig); - if (status != 0) { - printk(KERN_ERR "%s: Failed to write chconfig register\n", - DRIVER_NAME); - up(&the_tps->lock); - return status; - } - - chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); - the_tps->chgconf = chgconfig; - show_chgconfig(0, "chgconf", chgconfig); - - status = i2c_smbus_write_byte_data(&the_tps->client, - TPS_VDCDC1, vdcdc1); - - if (status != 0) - printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", - DRIVER_NAME); - else - pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); - - up(&the_tps->lock); - - return status; -} -EXPORT_SYMBOL(tps65013_set_low_pwr); - -/*-------------------------------------------------------------------------*/ - -static int __init tps_init(void) -{ - u32 tries = 3; - int status = -ENODEV; - - printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION); - - /* some boards have startup glitches */ - while (tries--) { - status = i2c_add_driver(&tps65010_driver); - if (the_tps) - break; - i2c_del_driver(&tps65010_driver); - if (!tries) { - printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME); - return -ENODEV; - } - pr_debug("%s: re-probe ...\n", DRIVER_NAME); - msleep(10); - } - -#ifdef CONFIG_ARM - if (machine_is_omap_osk()) { - - // FIXME: More should be placed in the initialization code - // of the submodules (DSP, ethernet, power management, - // board-osk.c). Careful: I2C is initialized "late". - - /* Let LED1 (D9) blink */ - tps65010_set_led(LED1, BLINK); - - /* Disable LED 2 (D2) */ - tps65010_set_led(LED2, OFF); - - /* Set GPIO 1 HIGH to disable VBUS power supply; - * OHCI driver powers it up/down as needed. - */ - tps65010_set_gpio_out_value(GPIO1, HIGH); - - /* Set GPIO 2 low to turn on LED D3 */ - tps65010_set_gpio_out_value(GPIO2, HIGH); - - /* Set GPIO 3 low to take ethernet out of reset */ - tps65010_set_gpio_out_value(GPIO3, LOW); - - /* gpio4 for VDD_DSP */ - - /* Enable LOW_PWR */ - tps65010_set_low_pwr(ON); - - /* Switch VLDO2 to 3.0V for AIC23 */ - tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); - - } else if (machine_is_omap_h2()) { - /* gpio3 for SD, gpio4 for VDD_DSP */ - - /* Enable LOW_PWR */ - tps65010_set_low_pwr(ON); - } else if (machine_is_omap_h3()) { - /* gpio4 for SD, gpio3 for VDD_DSP */ -#ifdef CONFIG_PM - /* Enable LOW_PWR */ - tps65013_set_low_pwr(ON); -#endif - } -#endif - - return status; -} -/* NOTE: this MUST be initialized before the other parts of the system - * that rely on it ... but after the i2c bus on which this relies. - * That is, much earlier than on PC-type systems, which don't often use - * I2C as a core system bus. - */ -subsys_initcall(tps_init); - -static void __exit tps_exit(void) -{ - i2c_del_driver(&tps65010_driver); -} -module_exit(tps_exit); - diff --git a/drivers/i2c/chips/x1205.c b/drivers/i2c/chips/x1205.c deleted file mode 100644 index 245fffa92db..00000000000 --- a/drivers/i2c/chips/x1205.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * x1205.c - An i2c driver for the Xicor X1205 RTC - * Copyright 2004 Karen Spearel - * Copyright 2005 Alessandro Zummo - * - * please send all reports to: - * kas11 at tampabay dot rr dot com - * a dot zummo at towertech dot it - * - * based on the other drivers in this same directory. - * - * 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. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/string.h> -#include <linux/bcd.h> -#include <linux/rtc.h> -#include <linux/list.h> - -#include <linux/x1205.h> - -#define DRV_VERSION "0.9.9" - -/* Addresses to scan: none. This chip is located at - * 0x6f and uses a two bytes register addressing. - * Two bytes need to be written to read a single register, - * while most other chips just require one and take the second - * one as the data to be written. To prevent corrupting - * unknown chips, the user must explicitely set the probe parameter. - */ - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Insmod parameters */ -I2C_CLIENT_INSMOD; -I2C_CLIENT_MODULE_PARM(hctosys, - "Set the system time from the hardware clock upon initialization"); - -/* offsets into CCR area */ - -#define CCR_SEC 0 -#define CCR_MIN 1 -#define CCR_HOUR 2 -#define CCR_MDAY 3 -#define CCR_MONTH 4 -#define CCR_YEAR 5 -#define CCR_WDAY 6 -#define CCR_Y2K 7 - -#define X1205_REG_SR 0x3F /* status register */ -#define X1205_REG_Y2K 0x37 -#define X1205_REG_DW 0x36 -#define X1205_REG_YR 0x35 -#define X1205_REG_MO 0x34 -#define X1205_REG_DT 0x33 -#define X1205_REG_HR 0x32 -#define X1205_REG_MN 0x31 -#define X1205_REG_SC 0x30 -#define X1205_REG_DTR 0x13 -#define X1205_REG_ATR 0x12 -#define X1205_REG_INT 0x11 -#define X1205_REG_0 0x10 -#define X1205_REG_Y2K1 0x0F -#define X1205_REG_DWA1 0x0E -#define X1205_REG_YRA1 0x0D -#define X1205_REG_MOA1 0x0C -#define X1205_REG_DTA1 0x0B -#define X1205_REG_HRA1 0x0A -#define X1205_REG_MNA1 0x09 -#define X1205_REG_SCA1 0x08 -#define X1205_REG_Y2K0 0x07 -#define X1205_REG_DWA0 0x06 -#define X1205_REG_YRA0 0x05 -#define X1205_REG_MOA0 0x04 -#define X1205_REG_DTA0 0x03 -#define X1205_REG_HRA0 0x02 -#define X1205_REG_MNA0 0x01 -#define X1205_REG_SCA0 0x00 - -#define X1205_CCR_BASE 0x30 /* Base address of CCR */ -#define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */ - -#define X1205_SR_RTCF 0x01 /* Clock failure */ -#define X1205_SR_WEL 0x02 /* Write Enable Latch */ -#define X1205_SR_RWEL 0x04 /* Register Write Enable */ - -#define X1205_DTR_DTR0 0x01 -#define X1205_DTR_DTR1 0x02 -#define X1205_DTR_DTR2 0x04 - -#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ - -/* Prototypes */ -static int x1205_attach(struct i2c_adapter *adapter); -static int x1205_detach(struct i2c_client *client); -static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); -static int x1205_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -static struct i2c_driver x1205_driver = { - .driver = { - .name = "x1205", - }, - .attach_adapter = &x1205_attach, - .detach_client = &x1205_detach, -}; - -struct x1205_data { - struct i2c_client client; - struct list_head list; - unsigned int epoch; -}; - -static const unsigned char days_in_mo[] = - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -static LIST_HEAD(x1205_clients); - -/* Workaround until the I2C subsytem will allow to send - * commands to a specific client. This function will send the command - * to the first client. - */ -int x1205_do_command(unsigned int cmd, void *arg) -{ - struct list_head *walk; - struct list_head *tmp; - struct x1205_data *data; - - list_for_each_safe(walk, tmp, &x1205_clients) { - data = list_entry(walk, struct x1205_data, list); - return x1205_command(&data->client, cmd, arg); - } - - return -ENODEV; -} - -#define is_leap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - -/* make sure the rtc_time values are in bounds */ -static int x1205_validate_tm(struct rtc_time *tm) -{ - int year = tm->tm_year + 1900; - - if ((tm->tm_year < 70) || (tm->tm_year > 255)) - return -EINVAL; - - if ((tm->tm_mon > 11) || (tm->tm_mday == 0)) - return -EINVAL; - - if (tm->tm_mday > days_in_mo[tm->tm_mon] - + ((tm->tm_mon == 1) && is_leap(year))) - return -EINVAL; - - if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60)) - return -EINVAL; - - return 0; -} - -/* - * In the routines that deal directly with the x1205 hardware, we use - * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch - * Epoch is initialized as 2000. Time is set to UTC. - */ -static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, - u8 reg_base) -{ - unsigned char dt_addr[2] = { 0, reg_base }; - static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; - - unsigned char buf[8], sr; - - struct i2c_msg msgs[] = { - { client->addr, 0, 2, sr_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, &sr }, /* read status */ - { client->addr, 0, 2, dt_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 8, buf }, /* read date */ - }; - - struct x1205_data *data = i2c_get_clientdata(client); - - /* read status register */ - if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); - return -EIO; - } - - /* check for battery failure */ - if (sr & X1205_SR_RTCF) { - dev_warn(&client->dev, - "Clock had a power failure, you must set the date.\n"); - return -EINVAL; - } - - /* read date registers */ - if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); - return -EIO; - } - - dev_dbg(&client->dev, - "%s: raw read data - sec=%02x, min=%02x, hr=%02x, " - "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", - __FUNCTION__, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - - tm->tm_sec = BCD2BIN(buf[CCR_SEC]); - tm->tm_min = BCD2BIN(buf[CCR_MIN]); - tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ - tm->tm_mday = BCD2BIN(buf[CCR_MDAY]); - tm->tm_mon = BCD2BIN(buf[CCR_MONTH]); - data->epoch = BCD2BIN(buf[CCR_Y2K]) * 100; - tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + data->epoch - 1900; - tm->tm_wday = buf[CCR_WDAY]; - - dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - - return 0; -} - -static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, - int datetoo, u8 reg_base) -{ - int i, err, xfer; - - unsigned char buf[8]; - - static const unsigned char wel[3] = { 0, X1205_REG_SR, - X1205_SR_WEL }; - - static const unsigned char rwel[3] = { 0, X1205_REG_SR, - X1205_SR_WEL | X1205_SR_RWEL }; - - static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; - - struct x1205_data *data = i2c_get_clientdata(client); - - /* check if all values in the tm struct are correct */ - if ((err = x1205_validate_tm(tm)) < 0) - return err; - - dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - - buf[CCR_SEC] = BIN2BCD(tm->tm_sec); - buf[CCR_MIN] = BIN2BCD(tm->tm_min); - - /* set hour and 24hr bit */ - buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL; - - /* should we also set the date? */ - if (datetoo) { - buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); - - /* month, 0 - 11 */ - buf[CCR_MONTH] = BIN2BCD(tm->tm_mon); - - /* year, since 1900 */ - buf[CCR_YEAR] = BIN2BCD(tm->tm_year + 1900 - data->epoch); - buf[CCR_WDAY] = tm->tm_wday & 0x07; - buf[CCR_Y2K] = BIN2BCD(data->epoch / 100); - } - - /* this sequence is required to unlock the chip */ - xfer = i2c_master_send(client, wel, 3); - if (xfer != 3) { - dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); - return -EIO; - } - - xfer = i2c_master_send(client, rwel, 3); - if (xfer != 3) { - dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); - return -EIO; - } - - /* write register's data */ - for (i = 0; i < (datetoo ? 8 : 3); i++) { - unsigned char rdata[3] = { 0, reg_base + i, buf[i] }; - - xfer = i2c_master_send(client, rdata, 3); - if (xfer != 3) { - dev_err(&client->dev, - "%s: xfer=%d addr=%02x, data=%02x\n", - __FUNCTION__, - xfer, rdata[1], rdata[2]); - return -EIO; - } - }; - - /* disable further writes */ - xfer = i2c_master_send(client, diswe, 3); - if (xfer != 3) { - dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); - return -EIO; - } - - return 0; -} - -static int x1205_get_dtrim(struct i2c_client *client, int *trim) -{ - unsigned char dtr; - static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR }; - - struct i2c_msg msgs[] = { - { client->addr, 0, 2, dtr_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, &dtr }, /* read dtr */ - }; - - /* read dtr register */ - if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); - return -EIO; - } - - dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr); - - *trim = 0; - - if (dtr & X1205_DTR_DTR0) - *trim += 20; - - if (dtr & X1205_DTR_DTR1) - *trim += 10; - - if (dtr & X1205_DTR_DTR2) - *trim = -*trim; - - return 0; -} - -static int x1205_get_atrim(struct i2c_client *client, int *trim) -{ - s8 atr; - static unsigned char atr_addr[2] = { 0, X1205_REG_ATR }; - - struct i2c_msg msgs[] = { - { client->addr, 0, 2, atr_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, &atr }, /* read atr */ - }; - - /* read atr register */ - if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); - return -EIO; - } - - dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr); - - /* atr is a two's complement value on 6 bits, - * perform sign extension. The formula is - * Catr = (atr * 0.25pF) + 11.00pF. - */ - if (atr & 0x20) - atr |= 0xC0; - - dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr); - - *trim = (atr * 250) + 11000; - - dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim); - - return 0; -} - -static int x1205_hctosys(struct i2c_client *client) -{ - int err; - - struct rtc_time tm; - struct timespec tv; - - err = x1205_command(client, X1205_CMD_GETDATETIME, &tm); - - if (err) { - dev_err(&client->dev, - "Unable to set the system clock\n"); - return err; - } - - /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary - * whether it stores the most close value or the value with partial - * seconds truncated. However, it is important that we use it to store - * the truncated value. This is because otherwise it is necessary, - * in an rtc sync function, to read both xtime.tv_sec and - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read - * of >32bits is not possible. So storing the most close value would - * slow down the sync API. So here we have the truncated value and - * the best guess is to add 0.5s. - */ - - tv.tv_nsec = NSEC_PER_SEC >> 1; - - /* WARNING: this is not the C library 'mktime' call, it is a built in - * inline function from include/linux/time.h. It expects (requires) - * the month to be in the range 1-12 - */ - - tv.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec); - - do_settimeofday(&tv); - - dev_info(&client->dev, - "setting the system clock to %d-%d-%d %d:%d:%d\n", - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, tm.tm_hour, tm.tm_min, - tm.tm_sec); - - return 0; -} - -struct x1205_limit -{ - unsigned char reg; - unsigned char mask; - unsigned char min; - unsigned char max; -}; - -static int x1205_validate_client(struct i2c_client *client) -{ - int i, xfer; - - /* Probe array. We will read the register at the specified - * address and check if the given bits are zero. - */ - static const unsigned char probe_zero_pattern[] = { - /* register, mask */ - X1205_REG_SR, 0x18, - X1205_REG_DTR, 0xF8, - X1205_REG_ATR, 0xC0, - X1205_REG_INT, 0x18, - X1205_REG_0, 0xFF, - }; - - static const struct x1205_limit probe_limits_pattern[] = { - /* register, mask, min, max */ - { X1205_REG_Y2K, 0xFF, 19, 20 }, - { X1205_REG_DW, 0xFF, 0, 6 }, - { X1205_REG_YR, 0xFF, 0, 99 }, - { X1205_REG_MO, 0xFF, 0, 12 }, - { X1205_REG_DT, 0xFF, 0, 31 }, - { X1205_REG_HR, 0x7F, 0, 23 }, - { X1205_REG_MN, 0xFF, 0, 59 }, - { X1205_REG_SC, 0xFF, 0, 59 }, - { X1205_REG_Y2K1, 0xFF, 19, 20 }, - { X1205_REG_Y2K0, 0xFF, 19, 20 }, - }; - - /* check that registers have bits a 0 where expected */ - for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) { - unsigned char buf; - - unsigned char addr[2] = { 0, probe_zero_pattern[i] }; - - struct i2c_msg msgs[2] = { - { client->addr, 0, 2, addr }, - { client->addr, I2C_M_RD, 1, &buf }, - }; - - xfer = i2c_transfer(client->adapter, msgs, 2); - if (xfer != 2) { - dev_err(&client->adapter->dev, - "%s: could not read register %x\n", - __FUNCTION__, addr[1]); - - return -EIO; - } - - if ((buf & probe_zero_pattern[i+1]) != 0) { - dev_err(&client->adapter->dev, - "%s: register=%02x, zero pattern=%d, value=%x\n", - __FUNCTION__, addr[1], i, buf); - - return -ENODEV; - } - } - - /* check limits (only registers with bcd values) */ - for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) { - unsigned char reg, value; - - unsigned char addr[2] = { 0, probe_limits_pattern[i].reg }; - - struct i2c_msg msgs[2] = { - { client->addr, 0, 2, addr }, - { client->addr, I2C_M_RD, 1, ® }, - }; - - xfer = i2c_transfer(client->adapter, msgs, 2); - - if (xfer != 2) { - dev_err(&client->adapter->dev, - "%s: could not read register %x\n", - __FUNCTION__, addr[1]); - - return -EIO; - } - - value = BCD2BIN(reg & probe_limits_pattern[i].mask); - - if (value > probe_limits_pattern[i].max || - value < probe_limits_pattern[i].min) { - dev_dbg(&client->adapter->dev, - "%s: register=%x, lim pattern=%d, value=%d\n", - __FUNCTION__, addr[1], i, value); - - return -ENODEV; - } - } - - return 0; -} - -static int x1205_attach(struct i2c_adapter *adapter) -{ - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); - - return i2c_probe(adapter, &addr_data, x1205_probe); -} - -int x1205_direct_attach(int adapter_id, - struct i2c_client_address_data *address_data) -{ - int err; - struct i2c_adapter *adapter = i2c_get_adapter(adapter_id); - - if (adapter) { - err = i2c_probe(adapter, - address_data, x1205_probe); - - i2c_put_adapter(adapter); - - return err; - } - - return -ENODEV; -} - -static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *client; - struct x1205_data *data; - - int err = 0; - - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - err = -ENODEV; - goto exit; - } - - if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - /* Initialize our structures */ - data->epoch = 2000; - - client = &data->client; - client->addr = address; - client->driver = &x1205_driver; - client->adapter = adapter; - - strlcpy(client->name, "x1205", I2C_NAME_SIZE); - - i2c_set_clientdata(client, data); - - /* Verify the chip is really an X1205 */ - if (kind < 0) { - if (x1205_validate_client(client) < 0) { - err = -ENODEV; - goto exit_kfree; - } - } - - /* Inform the i2c layer */ - if ((err = i2c_attach_client(client))) - goto exit_kfree; - - list_add(&data->list, &x1205_clients); - - dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - - /* If requested, set the system time */ - if (hctosys) - x1205_hctosys(client); - - return 0; - -exit_kfree: - kfree(data); - -exit: - return err; -} - -static int x1205_detach(struct i2c_client *client) -{ - int err; - struct x1205_data *data = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - - if ((err = i2c_detach_client(client))) - return err; - - list_del(&data->list); - - kfree(data); - - return 0; -} - -static int x1205_command(struct i2c_client *client, unsigned int cmd, - void *param) -{ - if (param == NULL) - return -EINVAL; - - if (!capable(CAP_SYS_TIME)) - return -EACCES; - - dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); - - switch (cmd) { - case X1205_CMD_GETDATETIME: - return x1205_get_datetime(client, param, X1205_CCR_BASE); - - case X1205_CMD_SETTIME: - return x1205_set_datetime(client, param, 0, - X1205_CCR_BASE); - - case X1205_CMD_SETDATETIME: - return x1205_set_datetime(client, param, 1, - X1205_CCR_BASE); - - case X1205_CMD_GETALARM: - return x1205_get_datetime(client, param, X1205_ALM0_BASE); - - case X1205_CMD_SETALARM: - return x1205_set_datetime(client, param, 1, - X1205_ALM0_BASE); - - case X1205_CMD_GETDTRIM: - return x1205_get_dtrim(client, param); - - case X1205_CMD_GETATRIM: - return x1205_get_atrim(client, param); - - default: - return -EINVAL; - } -} - -static int __init x1205_init(void) -{ - return i2c_add_driver(&x1205_driver); -} - -static void __exit x1205_exit(void) -{ - i2c_del_driver(&x1205_driver); -} - -MODULE_AUTHOR( - "Karen Spearel <kas11@tampabay.rr.com>, " - "Alessandro Zummo <a.zummo@towertech.it>"); -MODULE_DESCRIPTION("Xicor X1205 RTC driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -EXPORT_SYMBOL_GPL(x1205_do_command); -EXPORT_SYMBOL_GPL(x1205_direct_attach); - -module_init(x1205_init); -module_exit(x1205_exit); |
