max6875.c 6.9 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 53
static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};

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

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

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

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,
};

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

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

	down(&data->update_lock);

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

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

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

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

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

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

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

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

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

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

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

150
	return count;
151 152 153 154
}

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

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)
{
171 172
	struct i2c_client *real_client;
	struct i2c_client *fake_client;
173 174 175
	struct max6875_data *data;
	int err = 0;

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

181
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
182 183 184 185 186 187 188 189 190
				     | 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;
191 192
	memset(data, 0, sizeof(struct max6875_data));

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
	/* 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);
208 209
	init_MUTEX(&data->update_lock);

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

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

	return 0;

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

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

	err = i2c_detach_client(client);
	if (err) {
247
		dev_err(&client->dev, "i2c_detach_client() failed\n");
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
		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);