diff options
Diffstat (limited to 'drivers/i2c/chips/ds1337.c')
-rw-r--r-- | drivers/i2c/chips/ds1337.c | 410 |
1 files changed, 0 insertions, 410 deletions
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c deleted file mode 100644 index ec17d6b..0000000 --- a/drivers/i2c/chips/ds1337.c +++ /dev/null @@ -1,410 +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[1+16]; /* First byte is interpreted as address */ - struct i2c_msg msg[1]; - - dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__); - - /* Initialize all, including STATUS and CONTROL to zero */ - memset(buf, 0, sizeof(buf)); - - /* Write valid values in the date/time registers */ - buf[1+DS1337_REG_DAY] = 1; - buf[1+DS1337_REG_DATE] = 1; - buf[1+DS1337_REG_MONTH] = 1; - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = sizeof(buf); - msg[0].buf = &buf[0]; - - i2c_transfer(client->adapter, msg, 1); - } else { - /* Running: ensure that device is set in 24-hour mode */ - s32 val; - - val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR); - if ((val >= 0) && (val & (1 << 6))) - i2c_smbus_write_byte_data(client, DS1337_REG_HOUR, - val & 0x3f); - } -} - -static int ds1337_detach_client(struct i2c_client *client) -{ - int err; - struct ds1337_data *data = i2c_get_clientdata(client); - - if ((err = i2c_detach_client(client))) - return err; - - list_del(&data->list); - kfree(data); - return 0; -} - -static int __init ds1337_init(void) -{ - return i2c_add_driver(&ds1337_driver); -} - -static void __exit ds1337_exit(void) -{ - i2c_del_driver(&ds1337_driver); -} - -MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); -MODULE_DESCRIPTION("DS1337 RTC driver"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL_GPL(ds1337_do_command); - -module_init(ds1337_init); -module_exit(ds1337_exit); |