max6875.c 6.8 KB
Newer Older
1 2 3 4 5 6 7
/*
    max6875.c - driver for MAX6874/MAX6875

    Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>

    Based on i2c/chips/eeprom.c

8 9 10 11 12
    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
13

14
    This driver makes the user EEPROM available for read.
15

16
    The registers & config EEPROM should be accessed via i2c-dev.
17

18 19 20 21 22
    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.
23 24 25 26 27 28 29 30 31 32 33 34

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
35
#include <asm/semaphore.h>
36

37
/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
38
static unsigned short normal_i2c[] = {I2C_CLIENT_END};
39 40 41 42 43 44 45 46 47 48 49 50 51 52

/* Insmod parameters */
SENSORS_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 */
53
#define MAX6875_CMD_BLK_READ		0x84
54 55 56 57 58

/* Each client has this additional data */
struct max6875_data {
	struct i2c_client	client;
	struct semaphore	update_lock;
59 60 61 62

	u32			valid;
	u8			data[USER_EEPROM_SIZE];
	unsigned long		last_updated[USER_EEPROM_SLICES];
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
};

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 = {
	.owner		= THIS_MODULE,
	.name		= "max6875",
	.flags		= I2C_DF_NOTIFY,
	.attach_adapter	= max6875_attach_adapter,
	.detach_client	= max6875_detach_client,
};

78
static void max6875_update_slice(struct i2c_client *client, int slice)
79 80
{
	struct max6875_data *data = i2c_get_clientdata(client);
81 82
	int i, j, addr;
	u8 *buf;
83

84 85
	if (slice >= USER_EEPROM_SLICES)
		return;
86 87 88

	down(&data->update_lock);

89 90 91 92 93
	buf = &data->data[slice << SLICE_BITS];

	if (!(data->valid & (1 << slice)) ||
	    time_after(jiffies, data->last_updated[slice])) {

94
		dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
95

96
		data->valid &= ~(1 << slice);
97

98 99 100 101 102 103
		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;
104 105
		}

106 107 108 109 110 111
		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;
112 113
			}
		} else {
114
			for (i = 0; i < SLICE_SIZE; i++) {
115
				j = i2c_smbus_read_byte(client);
116 117
				if (j < 0) {
					goto exit_up;
118
				}
119
				buf[i] = j;
120 121
			}
		}
122 123
		data->last_updated[slice] = jiffies;
		data->valid |= (1 << slice);
124
	}
125
exit_up:
126 127 128
	up(&data->update_lock);
}

129 130
static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
			    size_t count)
131
{
132
	struct i2c_client *client = kobj_to_i2c_client(kobj);
133
	struct max6875_data *data = i2c_get_clientdata(client);
134
	int slice, max_slice;
135

136
	if (off > USER_EEPROM_SIZE)
137 138
		return 0;

139 140
	if (off + count > USER_EEPROM_SIZE)
		count = USER_EEPROM_SIZE - off;
141

142 143 144 145
	/* 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);
146

147
	memcpy(buf, &data->data[off], count);
148

149
	return count;
150 151 152 153
}

static struct bin_attribute user_eeprom_attr = {
	.attr = {
154 155
		.name = "eeprom",
		.mode = S_IRUGO,
156 157
		.owner = THIS_MODULE,
	},
158 159
	.size = USER_EEPROM_SIZE,
	.read = max6875_read,
160 161 162 163 164 165 166 167 168 169
};

static int max6875_attach_adapter(struct i2c_adapter *adapter)
{
	return i2c_detect(adapter, &addr_data, max6875_detect);
}

/* This function is called by i2c_detect */
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
{
170 171
	struct i2c_client *real_client;
	struct i2c_client *fake_client;
172 173 174
	struct max6875_data *data;
	int err = 0;

175
	/* Prevent 24rf08 corruption (in case of user error) */
176 177 178 179
	if (kind < 0)
		i2c_smbus_xfer(adapter, address, 0, 0, 0,
			       I2C_SMBUS_QUICK, NULL);

180
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
181 182 183 184 185 186 187 188 189
				     | I2C_FUNC_SMBUS_READ_BYTE))
		return 0;

	/* Only check even addresses */
	if (address & 1)
		return 0;

	if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL)))
		return -ENOMEM;
190 191
	memset(data, 0, sizeof(struct max6875_data));

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	/* A fake client is created on the odd address */
	if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
		err = -ENOMEM;
		goto exit_kfree1;
	}
	memset(fake_client, 0, sizeof(struct i2c_client));

	/* 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);
207 208
	init_MUTEX(&data->update_lock);

209 210 211 212 213 214 215
	/* 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;
216
	strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
217 218 219 220 221 222 223 224 225 226 227

	/* 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);
228 229 230

	return 0;

231 232 233 234 235
exit_detach:
	i2c_detach_client(real_client);
exit_kfree2:
	kfree(fake_client);
exit_kfree1:
236 237 238 239 240 241 242 243 244
	kfree(data);
	return err;
}

static int max6875_detach_client(struct i2c_client *client)
{
	int err;

	err = i2c_detach_client(client);
245
	if (err)
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
		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);