sonic-buildimage/platform/broadcom/sonic-platform-modules-cel/dx010/modules/mc24lc64t.c

143 lines
3.9 KiB
C
Raw Normal View History

/*
* mc24lc64t.c - driver for Microchip 24LC64T
*
* Copyright (C) 2017 Celestica Corp.
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
struct mc24lc64t_data {
struct i2c_client *fake_client;
struct mutex update_lock;
};
static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
unsigned long timeout, read_time, i = 0;
int status;
mutex_lock(&drvdata->update_lock);
if (i2c_smbus_write_byte_data(client, off>>8, off))
{
status = -EIO;
goto exit;
}
msleep(1);
begin:
if (i < count)
{
timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
do {
read_time = jiffies;
status = i2c_smbus_read_byte(client);
if (status >= 0)
{
buf[i++] = status;
goto begin;
}
} while (time_before(read_time, timeout));
status = -ETIMEDOUT;
goto exit;
}
status = count;
exit:
mutex_unlock(&drvdata->update_lock);
return status;
}
static struct bin_attribute mc24lc64t_bit_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
},
.size = 65536,
.read = mc24lc64t_read,
};
static int mc24lc64t_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
struct mc24lc64t_data *drvdata;
int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
| I2C_FUNC_SMBUS_READ_BYTE))
return -EPFNOSUPPORT;
if (!(drvdata = devm_kzalloc(&client->dev,
sizeof(struct mc24lc64t_data), GFP_KERNEL)))
return -ENOMEM;
drvdata->fake_client = i2c_new_dummy(client->adapter, client->addr + 1);
if (!drvdata->fake_client)
return -ENOMEM;
i2c_set_clientdata(client, drvdata);
mutex_init(&drvdata->update_lock);
err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
if (err)
i2c_unregister_device(drvdata->fake_client);
return err;
}
static int mc24lc64t_remove(struct i2c_client *client)
{
struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
i2c_unregister_device(drvdata->fake_client);
sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
return 0;
}
static const struct i2c_device_id mc24lc64t_id[] = {
{ "24lc64t", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mc24lc64t_id);
static struct i2c_driver mc24lc64t_driver = {
.driver = {
.name = "mc24lc64t",
.owner = THIS_MODULE,
},
.probe = mc24lc64t_probe,
.remove = mc24lc64t_remove,
.id_table = mc24lc64t_id,
};
module_i2c_driver(mc24lc64t_driver);
MODULE_AUTHOR("Abhisit Sangjan <asang@celestica.com>");
MODULE_DESCRIPTION("Microchip 24LC64T Driver");
MODULE_LICENSE("GPL");