mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 16:12:02 +00:00
fbae3fb154
I2C drivers can use the clientdata-pointer to point to private data. As I2C
devices are not really unregistered, but merely detached from their driver, it
used to be the drivers obligation to clear this pointer during remove() or a
failed probe(). As a couple of drivers forgot to do this, it was agreed that it
was cleaner if the i2c-core does this clearance when appropriate, as there is
no guarantee for the lifetime of the clientdata-pointer after remove() anyhow.
This feature was added to the core with commit
e4a7b9b04d
to fix the faulty drivers.
As there is no need anymore to clear the clientdata-pointer, remove all current
occurrences in the drivers to simplify the code and prevent confusion.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: Richard Purdie <rpurdie@linux.intel.com>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
210 lines
4.7 KiB
C
210 lines
4.7 KiB
C
/*
|
|
* I2C driver for Maxim MAX8925
|
|
*
|
|
* Copyright (C) 2009 Marvell International Ltd.
|
|
* Haojian Zhuang <haojian.zhuang@marvell.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/mfd/max8925.h>
|
|
#include <linux/slab.h>
|
|
|
|
#define RTC_I2C_ADDR 0x68
|
|
#define ADC_I2C_ADDR 0x47
|
|
|
|
static inline int max8925_read_device(struct i2c_client *i2c,
|
|
int reg, int bytes, void *dest)
|
|
{
|
|
int ret;
|
|
|
|
if (bytes > 1)
|
|
ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
|
|
else {
|
|
ret = i2c_smbus_read_byte_data(i2c, reg);
|
|
if (ret < 0)
|
|
return ret;
|
|
*(unsigned char *)dest = (unsigned char)ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static inline int max8925_write_device(struct i2c_client *i2c,
|
|
int reg, int bytes, void *src)
|
|
{
|
|
unsigned char buf[bytes + 1];
|
|
int ret;
|
|
|
|
buf[0] = (unsigned char)reg;
|
|
memcpy(&buf[1], src, bytes);
|
|
|
|
ret = i2c_master_send(i2c, buf, bytes + 1);
|
|
if (ret < 0)
|
|
return ret;
|
|
return 0;
|
|
}
|
|
|
|
int max8925_reg_read(struct i2c_client *i2c, int reg)
|
|
{
|
|
struct max8925_chip *chip = i2c_get_clientdata(i2c);
|
|
unsigned char data = 0;
|
|
int ret;
|
|
|
|
mutex_lock(&chip->io_lock);
|
|
ret = max8925_read_device(i2c, reg, 1, &data);
|
|
mutex_unlock(&chip->io_lock);
|
|
|
|
if (ret < 0)
|
|
return ret;
|
|
else
|
|
return (int)data;
|
|
}
|
|
EXPORT_SYMBOL(max8925_reg_read);
|
|
|
|
int max8925_reg_write(struct i2c_client *i2c, int reg,
|
|
unsigned char data)
|
|
{
|
|
struct max8925_chip *chip = i2c_get_clientdata(i2c);
|
|
int ret;
|
|
|
|
mutex_lock(&chip->io_lock);
|
|
ret = max8925_write_device(i2c, reg, 1, &data);
|
|
mutex_unlock(&chip->io_lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(max8925_reg_write);
|
|
|
|
int max8925_bulk_read(struct i2c_client *i2c, int reg,
|
|
int count, unsigned char *buf)
|
|
{
|
|
struct max8925_chip *chip = i2c_get_clientdata(i2c);
|
|
int ret;
|
|
|
|
mutex_lock(&chip->io_lock);
|
|
ret = max8925_read_device(i2c, reg, count, buf);
|
|
mutex_unlock(&chip->io_lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(max8925_bulk_read);
|
|
|
|
int max8925_bulk_write(struct i2c_client *i2c, int reg,
|
|
int count, unsigned char *buf)
|
|
{
|
|
struct max8925_chip *chip = i2c_get_clientdata(i2c);
|
|
int ret;
|
|
|
|
mutex_lock(&chip->io_lock);
|
|
ret = max8925_write_device(i2c, reg, count, buf);
|
|
mutex_unlock(&chip->io_lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(max8925_bulk_write);
|
|
|
|
int max8925_set_bits(struct i2c_client *i2c, int reg,
|
|
unsigned char mask, unsigned char data)
|
|
{
|
|
struct max8925_chip *chip = i2c_get_clientdata(i2c);
|
|
unsigned char value;
|
|
int ret;
|
|
|
|
mutex_lock(&chip->io_lock);
|
|
ret = max8925_read_device(i2c, reg, 1, &value);
|
|
if (ret < 0)
|
|
goto out;
|
|
value &= ~mask;
|
|
value |= data;
|
|
ret = max8925_write_device(i2c, reg, 1, &value);
|
|
out:
|
|
mutex_unlock(&chip->io_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(max8925_set_bits);
|
|
|
|
|
|
static const struct i2c_device_id max8925_id_table[] = {
|
|
{ "max8925", 0 },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, max8925_id_table);
|
|
|
|
static int __devinit max8925_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct max8925_platform_data *pdata = client->dev.platform_data;
|
|
static struct max8925_chip *chip;
|
|
|
|
if (!pdata) {
|
|
pr_info("%s: platform data is missing\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
|
|
if (chip == NULL)
|
|
return -ENOMEM;
|
|
chip->i2c = client;
|
|
chip->dev = &client->dev;
|
|
i2c_set_clientdata(client, chip);
|
|
dev_set_drvdata(chip->dev, chip);
|
|
mutex_init(&chip->io_lock);
|
|
|
|
chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR);
|
|
i2c_set_clientdata(chip->rtc, chip);
|
|
|
|
chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
|
|
i2c_set_clientdata(chip->adc, chip);
|
|
|
|
max8925_device_init(chip, pdata);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __devexit max8925_remove(struct i2c_client *client)
|
|
{
|
|
struct max8925_chip *chip = i2c_get_clientdata(client);
|
|
|
|
max8925_device_exit(chip);
|
|
i2c_unregister_device(chip->adc);
|
|
i2c_unregister_device(chip->rtc);
|
|
kfree(chip);
|
|
return 0;
|
|
}
|
|
|
|
static struct i2c_driver max8925_driver = {
|
|
.driver = {
|
|
.name = "max8925",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.probe = max8925_probe,
|
|
.remove = __devexit_p(max8925_remove),
|
|
.id_table = max8925_id_table,
|
|
};
|
|
|
|
static int __init max8925_i2c_init(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = i2c_add_driver(&max8925_driver);
|
|
if (ret != 0)
|
|
pr_err("Failed to register MAX8925 I2C driver: %d\n", ret);
|
|
return ret;
|
|
}
|
|
subsys_initcall(max8925_i2c_init);
|
|
|
|
static void __exit max8925_i2c_exit(void)
|
|
{
|
|
i2c_del_driver(&max8925_driver);
|
|
}
|
|
module_exit(max8925_i2c_exit);
|
|
|
|
MODULE_DESCRIPTION("I2C Driver for Maxim 8925");
|
|
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
|
|
MODULE_LICENSE("GPL");
|