1c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner/*
26858d49833b8c2aae74adcb593065797409d376eArce, Abraham * max6875.c - driver for MAX6874/MAX6875
36858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
46858d49833b8c2aae74adcb593065797409d376eArce, Abraham * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
56858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
66858d49833b8c2aae74adcb593065797409d376eArce, Abraham * Based on eeprom.c
76858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
86858d49833b8c2aae74adcb593065797409d376eArce, Abraham * The MAX6875 has a bank of registers and two banks of EEPROM.
96858d49833b8c2aae74adcb593065797409d376eArce, Abraham * Address ranges are defined as follows:
106858d49833b8c2aae74adcb593065797409d376eArce, Abraham *  * 0x0000 - 0x0046 = configuration registers
116858d49833b8c2aae74adcb593065797409d376eArce, Abraham *  * 0x8000 - 0x8046 = configuration EEPROM
126858d49833b8c2aae74adcb593065797409d376eArce, Abraham *  * 0x8100 - 0x82FF = user EEPROM
136858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
146858d49833b8c2aae74adcb593065797409d376eArce, Abraham * This driver makes the user EEPROM available for read.
156858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
166858d49833b8c2aae74adcb593065797409d376eArce, Abraham * The registers & config EEPROM should be accessed via i2c-dev.
176858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
186858d49833b8c2aae74adcb593065797409d376eArce, Abraham * The MAX6875 ignores the lowest address bit, so each chip responds to
196858d49833b8c2aae74adcb593065797409d376eArce, Abraham * two addresses - 0x50/0x51 and 0x52/0x53.
206858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
216858d49833b8c2aae74adcb593065797409d376eArce, Abraham * Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read
226858d49833b8c2aae74adcb593065797409d376eArce, Abraham * address, so this driver is destructive if loaded for the wrong EEPROM chip.
236858d49833b8c2aae74adcb593065797409d376eArce, Abraham *
246858d49833b8c2aae74adcb593065797409d376eArce, Abraham * This program is free software; you can redistribute it and/or modify
256858d49833b8c2aae74adcb593065797409d376eArce, Abraham * it under the terms of the GNU General Public License as published by
266858d49833b8c2aae74adcb593065797409d376eArce, Abraham * the Free Software Foundation; version 2 of the License.
276858d49833b8c2aae74adcb593065797409d376eArce, Abraham */
28c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
29c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#include <linux/kernel.h>
30c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#include <linux/init.h>
31c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#include <linux/module.h>
32c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#include <linux/slab.h>
33c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#include <linux/i2c.h>
345c085d369c2c4f18942ec8951466e186366d5c78Ingo Molnar#include <linux/mutex.h>
35c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
36c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner/* The MAX6875 can only read/write 16 bytes at a time */
37c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#define SLICE_SIZE			16
38c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#define SLICE_BITS			4
39c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
40c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner/* USER EEPROM is at addresses 0x8100 - 0x82FF */
41c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#define USER_EEPROM_BASE		0x8100
42c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#define USER_EEPROM_SIZE		0x0200
43c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner#define USER_EEPROM_SLICES		32
44c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
45c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner/* MAX6875 commands */
46bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner#define MAX6875_CMD_BLK_READ		0x84
47c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
48c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner/* Each client has this additional data */
49c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardnerstruct max6875_data {
50bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	struct i2c_client	*fake_client;
515c085d369c2c4f18942ec8951466e186366d5c78Ingo Molnar	struct mutex		update_lock;
52bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner
53bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	u32			valid;
54bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	u8			data[USER_EEPROM_SIZE];
55bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	unsigned long		last_updated[USER_EEPROM_SLICES];
56c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner};
57c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
58bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardnerstatic void max6875_update_slice(struct i2c_client *client, int slice)
59c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner{
60c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	struct max6875_data *data = i2c_get_clientdata(client);
61bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	int i, j, addr;
62bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	u8 *buf;
63c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
64bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	if (slice >= USER_EEPROM_SLICES)
65bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		return;
66c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
675c085d369c2c4f18942ec8951466e186366d5c78Ingo Molnar	mutex_lock(&data->update_lock);
68c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
69bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	buf = &data->data[slice << SLICE_BITS];
70bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner
71bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	if (!(data->valid & (1 << slice)) ||
72bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	    time_after(jiffies, data->last_updated[slice])) {
73bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner
74a8decc658a8800e61f13b9240125f2a34d7fd3f5Greg Kroah-Hartman		dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
75c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
76bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		data->valid &= ~(1 << slice);
77c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
78bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		addr = USER_EEPROM_BASE + (slice << SLICE_BITS);
79bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner
80bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		/* select the eeprom address */
81bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
82bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner			dev_err(&client->dev, "address set failed\n");
83bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner			goto exit_up;
84c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner		}
85c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
86bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		if (i2c_check_functionality(client->adapter,
87bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner					    I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
88bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner			if (i2c_smbus_read_i2c_block_data(client,
89bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner							  MAX6875_CMD_BLK_READ,
904b2643d7d9bdcd776749e17f73c168ddf02e93cbJean Delvare							  SLICE_SIZE,
91bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner							  buf) != SLICE_SIZE) {
92bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner				goto exit_up;
93c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner			}
94c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner		} else {
95bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner			for (i = 0; i < SLICE_SIZE; i++) {
96c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner				j = i2c_smbus_read_byte(client);
97bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner				if (j < 0) {
98bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner					goto exit_up;
99c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner				}
100bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner				buf[i] = j;
101c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner			}
102c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner		}
103bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		data->last_updated[slice] = jiffies;
104bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		data->valid |= (1 << slice);
105c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	}
106bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardnerexit_up:
1075c085d369c2c4f18942ec8951466e186366d5c78Ingo Molnar	mutex_unlock(&data->update_lock);
108c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner}
109c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
1102c3c8bea608866d8bd9dcf92657d57fdcac011c5Chris Wrightstatic ssize_t max6875_read(struct file *filp, struct kobject *kobj,
11191a6902958f052358899f58683d44e36228d85c2Zhang Rui			    struct bin_attribute *bin_attr,
11291a6902958f052358899f58683d44e36228d85c2Zhang Rui			    char *buf, loff_t off, size_t count)
113c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner{
114bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	struct i2c_client *client = kobj_to_i2c_client(kobj);
115c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	struct max6875_data *data = i2c_get_clientdata(client);
116bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	int slice, max_slice;
117c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
118bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	if (off > USER_EEPROM_SIZE)
119c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner		return 0;
120c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
121bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	if (off + count > USER_EEPROM_SIZE)
122bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		count = USER_EEPROM_SIZE - off;
123c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
124bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	/* refresh slices which contain requested bytes */
125bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	max_slice = (off + count - 1) >> SLICE_BITS;
126bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
127bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		max6875_update_slice(client, slice);
128c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
129bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	memcpy(buf, &data->data[off], count);
130c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
131bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	return count;
132c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner}
133c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
134c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardnerstatic struct bin_attribute user_eeprom_attr = {
135c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	.attr = {
136bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		.name = "eeprom",
137bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		.mode = S_IRUGO,
138c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	},
139bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	.size = USER_EEPROM_SIZE,
140bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	.read = max6875_read,
141c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner};
142c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
143b835d7fbd54c42d7b9abb5e8a64f32690ebfad43Jean Delvarestatic int max6875_probe(struct i2c_client *client,
144b835d7fbd54c42d7b9abb5e8a64f32690ebfad43Jean Delvare			 const struct i2c_device_id *id)
145c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner{
146bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	struct i2c_adapter *adapter = client->adapter;
147b835d7fbd54c42d7b9abb5e8a64f32690ebfad43Jean Delvare	struct max6875_data *data;
148b835d7fbd54c42d7b9abb5e8a64f32690ebfad43Jean Delvare	int err;
149c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
15017f990c87a1e5addc49b99a53b3d2a2fac9680e9Ben Gardner	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
151bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner				     | I2C_FUNC_SMBUS_READ_BYTE))
152bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare		return -ENODEV;
153bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner
154b835d7fbd54c42d7b9abb5e8a64f32690ebfad43Jean Delvare	/* Only bind to even addresses */
155bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	if (client->addr & 1)
156bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare		return -ENODEV;
157bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare
1585263ebb51eb098b01caf229498c954999117e4a7Deepak Saxena	if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
159bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		return -ENOMEM;
160c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
161bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	/* A fake client is created on the odd address */
162bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1);
163bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	if (!data->fake_client) {
164bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner		err = -ENOMEM;
165bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare		goto exit_kfree;
166bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	}
167bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner
168bc769ff8f5f6e3d249bfde082653e5bf1c2b5698Ben Gardner	/* Init real i2c_client */
169bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	i2c_set_clientdata(client, data);
1705c085d369c2c4f18942ec8951466e186366d5c78Ingo Molnar	mutex_init(&data->update_lock);
171c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
172bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
1737d9db67febf67dd76329a9dd8f97cf4611a8ac2eJean Delvare	if (err)
174bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare		goto exit_remove_fake;
175c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
176c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	return 0;
177c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
178bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvareexit_remove_fake:
179bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	i2c_unregister_device(data->fake_client);
180bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvareexit_kfree:
181c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	kfree(data);
182c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	return err;
183c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner}
184c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
185bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvarestatic int max6875_remove(struct i2c_client *client)
186c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner{
1877d9db67febf67dd76329a9dd8f97cf4611a8ac2eJean Delvare	struct max6875_data *data = i2c_get_clientdata(client);
1887d9db67febf67dd76329a9dd8f97cf4611a8ac2eJean Delvare
189bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	i2c_unregister_device(data->fake_client);
190c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
191bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
192bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	kfree(data);
1937d9db67febf67dd76329a9dd8f97cf4611a8ac2eJean Delvare
194c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner	return 0;
195c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner}
196c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
197bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvarestatic const struct i2c_device_id max6875_id[] = {
198bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	{ "max6875", 0 },
199bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	{ }
200bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare};
201bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare
202bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvarestatic struct i2c_driver max6875_driver = {
203bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	.driver = {
204bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare		.name	= "max6875",
205bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	},
206bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	.probe		= max6875_probe,
207bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	.remove		= max6875_remove,
208bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare	.id_table	= max6875_id,
209bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare};
210bd8d421f7ca9f8da3d820d28379d796500f69529Jean Delvare
211a64fe2ed76614d37abb6966a67f4f39d10efba3cAxel Linmodule_i2c_driver(max6875_driver);
212c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen Gardner
213c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen GardnerMODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
214c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen GardnerMODULE_DESCRIPTION("MAX6875 driver");
215c3bc4caedd84ad03360cb9ec04b6c44ab314588bBen GardnerMODULE_LICENSE("GPL");
216