max6875.c 6.7 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

    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>
34
#include <linux/mutex.h>
35

36
/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
37
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
38 39

/* Insmod parameters */
40
I2C_CLIENT_INSMOD_1(max6875);
41 42 43 44 45 46 47 48 49 50 51

/* 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 */
52
#define MAX6875_CMD_BLK_READ		0x84
53 54 55 56

/* Each client has this additional data */
struct max6875_data {
	struct i2c_client	client;
57
	struct mutex		update_lock;
58 59 60 61

	u32			valid;
	u8			data[USER_EEPROM_SIZE];
	unsigned long		last_updated[USER_EEPROM_SLICES];
62 63 64 65 66 67 68 69
};

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 = {
70 71 72
	.driver = {
		.name	= "max6875",
	},
73 74 75 76
	.attach_adapter	= max6875_attach_adapter,
	.detach_client	= max6875_detach_client,
};

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

83 84
	if (slice >= USER_EEPROM_SLICES)
		return;
85

86
	mutex_lock(&data->update_lock);
87

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

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

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

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

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

105 106 107 108
		if (i2c_check_functionality(client->adapter,
					    I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
			if (i2c_smbus_read_i2c_block_data(client,
							  MAX6875_CMD_BLK_READ,
109
							  SLICE_SIZE,
110 111
							  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
	mutex_unlock(&data->update_lock);
127 128
}

129 130 131
static ssize_t max6875_read(struct kobject *kobj,
			    struct bin_attribute *bin_attr,
			    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 159
	.size = USER_EEPROM_SIZE,
	.read = max6875_read,
160 161 162 163
};

static int max6875_attach_adapter(struct i2c_adapter *adapter)
{
164
	return i2c_probe(adapter, &addr_data, max6875_detect);
165 166
}

167
/* This function is called by i2c_probe */
168 169
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
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
176 177 178 179 180 181 182
				     | I2C_FUNC_SMBUS_READ_BYTE))
		return 0;

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

183
	if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
184
		return -ENOMEM;
185

186
	/* A fake client is created on the odd address */
187
	if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
188 189 190 191 192 193 194 195 196 197 198 199
		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);
200
	mutex_init(&data->update_lock);
201

202
	/* Init fake client data */
203
	i2c_set_clientdata(fake_client, NULL);
204 205 206 207
	fake_client->addr = address | 1;
	fake_client->adapter = adapter;
	fake_client->driver = &max6875_driver;
	fake_client->flags = 0;
208
	strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
209 210 211 212 213

	if ((err = i2c_attach_client(real_client)) != 0)
		goto exit_kfree2;

	if ((err = i2c_attach_client(fake_client)) != 0)
214
		goto exit_detach1;
215

216 217 218
	err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
	if (err)
		goto exit_detach2;
219 220 221

	return 0;

222 223 224
exit_detach2:
	i2c_detach_client(fake_client);
exit_detach1:
225 226 227 228
	i2c_detach_client(real_client);
exit_kfree2:
	kfree(fake_client);
exit_kfree1:
229 230 231 232
	kfree(data);
	return err;
}

233
/* Will be called for both the real client and the fake client */
234 235 236
static int max6875_detach_client(struct i2c_client *client)
{
	int err;
237 238 239 240 241
	struct max6875_data *data = i2c_get_clientdata(client);

	/* data is NULL for the fake client */
	if (data)
		sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
242 243

	err = i2c_detach_client(client);
244
	if (err)
245
		return err;
246 247 248 249 250

	if (data)		/* real client */
		kfree(data);
	else			/* fake client */
		kfree(client);
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
	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);