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