[lm-sensors] [PATCH 1/1] [i2c] support for MAX8821 led charge pump with mono audio amp and dual LDO.
Rodolfo Giometti
giometti at enneenne.com
Mon Sep 22 15:42:31 CEST 2008
From: Rodolfo Giometti <giometti at linux.it>
Signed-off-by: Rodolfo Giometti <giometti at linux.it>
---
drivers/i2c/chips/Kconfig | 12 +
drivers/i2c/chips/Makefile | 1 +
drivers/i2c/chips/max8821.c | 707 +++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c/max8821.h | 32 ++
4 files changed, 752 insertions(+), 0 deletions(-)
create mode 100644 drivers/i2c/chips/max8821.c
create mode 100644 include/linux/i2c/max8821.h
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index a95cb94..9c8b72d 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -152,6 +152,18 @@ config SENSORS_MAX6875
This driver can also be built as a module. If so, the module
will be called max6875.
+config SENSORS_MAX8821
+ tristate "Maxim MAX8821 Led charge pump, mono audio amp and dual LDO"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for the Maxim MAX8821
+ white led charge pump with mono class D audio amp and dual LDO.
+
+ This provides an interface to manage internal subsystems.
+
+ This driver can also be built as a module. If so, the module
+ will be called max8821.
+
config SENSORS_TSL2550
tristate "Taos TSL2550 ambient light sensor"
depends on EXPERIMENTAL
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 39e3e69..f55e4d7 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_AT24) += at24.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
+obj-$(CONFIG_SENSORS_MAX8821) += max8821.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_PCF8575) += pcf8575.o
diff --git a/drivers/i2c/chips/max8821.c b/drivers/i2c/chips/max8821.c
new file mode 100644
index 0000000..1225681
--- /dev/null
+++ b/drivers/i2c/chips/max8821.c
@@ -0,0 +1,707 @@
+/*
+ * max8821.c - driver for white led charge pump with mono class D
+ * audio amp and dual LDO
+ *
+ * Copyright (C) 2008 Rodolfo Giometti <giometti at linux.it>
+ * Copyright (C) 2008 Eurotech S.p.A. <info at eurotech.it>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/leds.h>
+
+#include <linux/i2c/max8821.h>
+
+#define DRIVER_VERSION "0.40.0"
+
+/*
+ * Defines
+ */
+
+#define LED1_CNTL 0x00
+#define LED2_CNTL 0x01
+#define LED3_CNTL 0x02
+#define LED4_CNTL 0x03
+#define LED5_CNTL 0x04
+#define LED6_CNTL 0x05
+#define INT_MASK 0x1f
+#define LED_EN 0x0a
+#define LDO1_CNTL 0x0b
+#define LDO2_CNTL 0x0c
+#define LDO_EN (1 << 5)
+#define VOLT_MASK 0x0f
+#define AUDIO_CNTL 0x0d
+#define CLK_MASK (3 << 5)
+#define CLK_1100K (0 << 5)
+#define CLK_1400K (1 << 5)
+#define CLK_1250K (2 << 5)
+#define AMP_EN (1 << 4)
+#define GAIN_MASK 0x0f
+#define DB_TO_IDX(dB) ((((dB) + 3) / 3) & GAIN_MASK)
+#define IDX_TO_DB(idx) ((((idx) & GAIN_MASK) * 3) - 3)
+
+static u8 led_en_lut[] = {
+ (1 << 7), (1 << 6), (1 << 5), (1 << 4), (1 << 2), (1 << 0),
+};
+static u8 led_dis_lut[] = {
+ (1 << 7), (1 << 6), (1 << 5), (1 << 4), (3 << 2), (3 << 0),
+};
+
+static int ldo_voltage_lut[][16] = {
+ { 1200, 1300, 1500, 1600, 1800, 1900, 2000, 2300,
+ 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, },
+ { 1500, 1600, 1800, 2000, 2200, 2300, 2400, 2500,
+ 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, },
+};
+
+/*
+ * Structs
+ */
+
+struct max8821_data;
+struct max8821_led {
+ struct max8821_data *data; /* back link */
+ struct led_classdev dev;
+ int new_level;
+ struct work_struct work;
+};
+
+struct max8821_data {
+ struct i2c_client *client;
+ struct mutex update_lock;
+
+ struct max8821_led led[6];
+};
+
+/*
+ * Management functions
+ */
+
+static int write_led_brightness(struct i2c_client *client, int id,
+ unsigned int brightness)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ u8 addr = LED1_CNTL + id;
+ int ret;
+
+ /* By design leds should operate in 0-255 range but we have 0-31 */
+ if (brightness > 255)
+ return -EINVAL;
+ brightness = brightness * INT_MASK / 255;
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_read_byte_data(client, addr);
+ if (ret < 0)
+ goto exit;
+
+ ret &= ~INT_MASK;
+ ret |= brightness;
+
+ ret = i2c_smbus_write_byte_data(client, addr, ret);
+ if (ret < 0)
+ goto exit;
+
+ ret = i2c_smbus_read_byte_data(client, LED_EN);
+ if (ret < 0)
+ goto exit;
+
+ if (brightness)
+ ret |= led_en_lut[id];
+ else
+ ret &= ~led_dis_lut[id];
+
+ ret = i2c_smbus_write_byte_data(client, LED_EN, ret);
+ if (ret < 0)
+ goto exit;
+
+ ret = 0;
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static int read_ldo_power(struct i2c_client *client, int id, char *buf)
+{
+ u8 addr = LDO1_CNTL + id;
+ int ret = i2c_smbus_read_byte_data(client, addr);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d", !!(ret & LDO_EN));
+}
+
+static int write_ldo_power(struct i2c_client *client, int id, int val)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ u8 addr = LDO1_CNTL + id;
+ int ret;
+
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_read_byte_data(client, addr);
+ if (ret < 0)
+ goto exit;
+
+ if (val)
+ ret |= LDO_EN;
+ else
+ ret &= ~LDO_EN;
+
+ ret = i2c_smbus_write_byte_data(client, addr, ret);
+ if (ret < 0)
+ goto exit;
+
+ ret = 0;
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static int read_ldo_voltage(struct i2c_client *client, int id, char *buf)
+{
+ u8 addr = LDO1_CNTL + id;
+ int ret = i2c_smbus_read_byte_data(client, addr);
+ if (ret < 0)
+ return ret;
+
+ ret = ldo_voltage_lut[id][ret & VOLT_MASK];
+ return sprintf(buf, "%d", ret);
+}
+
+static int write_ldo_voltage(struct i2c_client *client, int id, int val)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ u8 addr = LDO1_CNTL + id;
+ int i, ret;
+
+ if (val < ldo_voltage_lut[id][0])
+ return -EINVAL;
+
+ for (i = 0; i < 16; i++)
+ if (val <= ldo_voltage_lut[id][i])
+ break;
+ if (i >= 16)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ ret = i2c_smbus_read_byte_data(client, addr);
+ if (ret < 0)
+ goto exit;
+
+ ret &= ~VOLT_MASK;
+ ret |= i;
+
+ ret = i2c_smbus_write_byte_data(client, addr, ret);
+ if (ret < 0)
+ goto exit;
+ ret = 0;
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static ssize_t write_audio_power(struct i2c_client *client, int val)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_read_byte_data(client, AUDIO_CNTL);
+ if (ret < 0)
+ goto exit;
+
+ if (val)
+ ret |= AMP_EN;
+ else
+ ret &= ~AMP_EN;
+
+ ret = i2c_smbus_write_byte_data(client, AUDIO_CNTL, ret);
+ if (ret < 0)
+ goto exit;
+
+ ret = 0;
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static int write_audio_clock(struct i2c_client *client, int val)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ switch (val) {
+ case 1100:
+ val = CLK_1100K;
+ break;
+ case 1400:
+ val = CLK_1400K;
+ break;
+ case 1250:
+ val = CLK_1250K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_read_byte_data(client, AUDIO_CNTL);
+ if (ret < 0)
+ goto exit;
+
+ ret &= ~CLK_MASK;
+ ret |= val;
+
+ ret = i2c_smbus_write_byte_data(client, AUDIO_CNTL, ret);
+ if (ret < 0)
+ goto exit;
+ ret = 0;
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static int write_audio_gain(struct i2c_client *client, int val)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ if (val < -3 || val > 24)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_read_byte_data(client, AUDIO_CNTL);
+ if (ret < 0)
+ goto exit;
+
+ ret &= ~GAIN_MASK;
+ ret |= DB_TO_IDX(val);
+
+ ret = i2c_smbus_write_byte_data(client, AUDIO_CNTL, ret);
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/*
+ * SysFS support
+ */
+
+/* LDO1 */
+static ssize_t show_ldo1_power(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_ldo_power(to_i2c_client(dev), MAX8821_LDO1, buf);
+}
+
+static ssize_t store_ldo1_power(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_ldo_power(to_i2c_client(dev), MAX8821_LDO1,
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(ldo1_power, S_IWUSR | S_IRUGO,
+ show_ldo1_power, store_ldo1_power);
+
+static ssize_t show_ldo1_voltage(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_ldo_voltage(to_i2c_client(dev), MAX8821_LDO1, buf);
+}
+
+static ssize_t store_ldo1_voltage(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_ldo_voltage(to_i2c_client(dev), MAX8821_LDO1,
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(ldo1_voltage, S_IWUSR | S_IRUGO,
+ show_ldo1_voltage, store_ldo1_voltage);
+
+/* LDO2 */
+static ssize_t show_ldo2_power(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_ldo_power(to_i2c_client(dev), MAX8821_LDO2, buf);
+}
+
+static ssize_t store_ldo2_power(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_ldo_power(to_i2c_client(dev), MAX8821_LDO2,
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(ldo2_power, S_IWUSR | S_IRUGO,
+ show_ldo2_power, store_ldo2_power);
+
+static ssize_t show_ldo2_voltage(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_ldo_voltage(to_i2c_client(dev), MAX8821_LDO2, buf);
+}
+
+static ssize_t store_ldo2_voltage(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_ldo_voltage(to_i2c_client(dev), MAX8821_LDO2,
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(ldo2_voltage, S_IWUSR | S_IRUGO,
+ show_ldo2_voltage, store_ldo2_voltage);
+
+/* Audio */
+static ssize_t show_audio_power(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = i2c_smbus_read_byte_data(to_i2c_client(dev), AUDIO_CNTL);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d", !!(ret & AMP_EN));
+}
+
+static ssize_t store_audio_power(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_audio_power(to_i2c_client(dev),
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(audio_power, S_IWUSR | S_IRUGO,
+ show_audio_power, store_audio_power);
+
+static ssize_t show_audio_clock(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = i2c_smbus_read_byte_data(to_i2c_client(dev), AUDIO_CNTL);
+ if (ret < 0)
+ return ret;
+
+ if ((ret & CLK_MASK) == CLK_1100K)
+ strncpy(buf, "1100", 4);
+ if ((ret & CLK_MASK) == CLK_1400K)
+ strncpy(buf, "1400", 4);
+ if ((ret & CLK_MASK) == CLK_1250K)
+ strncpy(buf, "1250", 4);
+ return 4;
+}
+
+static ssize_t store_audio_clock(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_audio_clock(to_i2c_client(dev),
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+
+static DEVICE_ATTR(audio_clock, S_IWUSR | S_IRUGO,
+ show_audio_clock, store_audio_clock);
+
+static ssize_t show_audio_gain(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = i2c_smbus_read_byte_data(to_i2c_client(dev), AUDIO_CNTL);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d", IDX_TO_DB(ret));
+}
+
+static ssize_t store_audio_gain(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = write_audio_gain(to_i2c_client(dev),
+ strict_strtol(buf, NULL, 10));
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(audio_gain, S_IWUSR | S_IRUGO,
+ show_audio_gain, store_audio_gain);
+
+static struct attribute *max8821_attributes[] = {
+ &dev_attr_ldo1_power.attr,
+ &dev_attr_ldo1_voltage.attr,
+ &dev_attr_ldo2_power.attr,
+ &dev_attr_ldo2_voltage.attr,
+ &dev_attr_audio_power.attr,
+ &dev_attr_audio_clock.attr,
+ &dev_attr_audio_gain.attr,
+ NULL
+};
+
+static const struct attribute_group max8821_attr_group = {
+ .attrs = max8821_attributes,
+};
+
+/*
+ * Led support
+ */
+
+static void max8821_led_set_work(struct work_struct *p)
+{
+ struct max8821_led *led = container_of(p, struct max8821_led, work);
+ struct max8821_data *data = led->data;
+ struct i2c_client *client = data->client;
+
+ write_led_brightness(client, led - &data->led[0], led->new_level);
+}
+
+static void max8821_led_set(struct led_classdev *p, enum led_brightness value)
+{
+ struct max8821_led *led = container_of(p, struct max8821_led, dev);
+
+ led->new_level = value;
+ schedule_work(&led->work);
+}
+
+/*
+ * Device init function
+ */
+
+static int max8821_init_client(struct i2c_client *client,
+ struct max8821_platform_data *pdata)
+{
+ int i, ret;
+
+ /* Set the platform defaults */
+ for (i = MAX8821_LED1; i <= MAX8821_LED6; i++) {
+ ret = write_led_brightness(client, i, pdata->led[i].brightness);
+ if (ret)
+ dev_warn(&client->dev,
+ "unable to init LED%d brightness to %d\n",
+ i + 1, pdata->led[i].brightness);
+ }
+
+ for (i = MAX8821_LDO1; i <= MAX8821_LDO2; i++) {
+ ret = write_ldo_power(client, i, pdata->ldo[i].power);
+ if (ret)
+ dev_warn(&client->dev,
+ "unable to init LDO%d power to %d\n",
+ i + 1, pdata->ldo[i].power);
+ if (pdata->ldo[i].power == 0)
+ continue;
+
+ ret = write_ldo_voltage(client, i, pdata->ldo[i].voltage);
+ if (ret)
+ dev_warn(&client->dev,
+ "unable to init LDO%d voltage to %d\n",
+ i + 1, pdata->ldo[i].voltage);
+ }
+
+ ret = write_audio_power(client, pdata->audio.power);
+ if (ret)
+ dev_warn(&client->dev,
+ "unable to init audio power to %d\n",
+ pdata->ldo[i].power);
+ if (pdata->audio.power == 1) {
+ ret = write_audio_clock(client, pdata->audio.clock);
+ if (ret)
+ dev_warn(&client->dev,
+ "unable to init audio clock to %d\n",
+ pdata->audio.clock);
+ ret = write_audio_gain(client, pdata->audio.gain);
+ if (ret)
+ dev_warn(&client->dev,
+ "unable to init audio gain to %d\n",
+ pdata->audio.gain);
+ }
+
+ return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+
+static struct max8821_platform_data defs; /* all values are set to '0' */
+
+static struct i2c_driver max8821_driver;
+static int __devinit max8821_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct max8821_data *data;
+ struct max8821_platform_data *pdata;
+ int i, ret = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
+ | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+ ret = -EIO;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct max8821_data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ data->client = client;
+ i2c_set_clientdata(client, data);
+
+ /* Check platform data */
+ pdata = client->dev.platform_data;
+ if (!pdata)
+ pdata = &defs;
+ for (i = MAX8821_LED1; i <= MAX8821_LED6; i++)
+ if (pdata->led[i].name) {
+ dev_dbg(&client->dev, "led%d:\n", i + 1);
+ dev_dbg(&client->dev, "\tname %s\n",
+ pdata->led[i].name);
+ dev_dbg(&client->dev, "\tdefault brightness %d\n",
+ pdata->led[i].brightness);
+#ifdef CONFIG_LEDS_TRIGGERS
+ dev_dbg(&client->dev, "\ttrigger %s\n",
+ pdata->led[i].trigger);
+#endif
+ }
+ for (i = MAX8821_LDO1; i <= MAX8821_LDO2; i++)
+ if (pdata->ldo[i].power) {
+ dev_dbg(&client->dev, "LDO%d:\n", i + 1);
+ dev_dbg(&client->dev, "\tpower %d\n",
+ pdata->ldo[i].power);
+ dev_dbg(&client->dev, "\tvoltage %dV\n",
+ pdata->ldo[i].voltage);
+ }
+ if (pdata->audio.power) {
+ dev_dbg(&client->dev, "audio:\n");
+ dev_dbg(&client->dev, "\tpower %d\n", pdata->audio.power);
+ dev_dbg(&client->dev, "\tclock %dkHz\n", pdata->audio.clock);
+ dev_dbg(&client->dev, "\tgain %dV\n", pdata->audio.gain);
+ }
+
+ mutex_init(&data->update_lock);
+
+ /* Initialize the MAX8821 chip */
+ ret = max8821_init_client(client, pdata);
+ if (ret)
+ goto exit_kfree;
+
+ /* Register the led devices */
+ for (i = MAX8821_LED1; i <= MAX8821_LED6; i++)
+ if (pdata->led[i].name) {
+ data->led[i].data = data;
+ data->led[i].dev.name = pdata->led[i].name;
+ data->led[i].dev.brightness = pdata->led[i].brightness;
+ data->led[i].dev.brightness_set = max8821_led_set;
+#ifdef CONFIG_LEDS_TRIGGERS
+ data->led[i].dev.default_trigger =
+ pdata->led[i].trigger;
+#endif
+ INIT_WORK(&data->led[i].work, max8821_led_set_work);
+ ret = led_classdev_register(&client->dev,
+ &data->led[i].dev);
+ if (ret < 0)
+ dev_warn(&client->dev, "unable to register "
+ "led%d into the system\n",
+ i + 1);
+ }
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &max8821_attr_group);
+ if (ret)
+ goto exit_kfree;
+
+ dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
+
+ return 0;
+
+exit_kfree:
+ kfree(data);
+exit:
+ return ret;
+}
+
+static int __devexit max8821_remove(struct i2c_client *client)
+{
+ struct max8821_data *data = i2c_get_clientdata(client);
+ int i;
+
+ for (i = MAX8821_LED1; i <= MAX8821_LED6; i++)
+ led_classdev_unregister(&data->led[i].dev);
+
+ sysfs_remove_group(&client->dev.kobj, &max8821_attr_group);
+
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static const struct i2c_device_id max8821_id[] = {
+ { "max8821", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max8821_id);
+
+static struct i2c_driver max8821_driver = {
+ .driver = {
+ .name = "max8821",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8821_probe,
+ .remove = __devexit_p(max8821_remove),
+ .id_table = max8821_id,
+};
+
+static int __init max8821_init(void)
+{
+ return i2c_add_driver(&max8821_driver);
+}
+
+static void __exit max8821_exit(void)
+{
+ i2c_del_driver(&max8821_driver);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti at linux.it>");
+MODULE_DESCRIPTION("MAX8821 led charge pump with mono class D audio amp and "
+ "dual LDO");
+MODULE_LICENSE("GPL");
+
+module_init(max8821_init);
+module_exit(max8821_exit);
diff --git a/include/linux/i2c/max8821.h b/include/linux/i2c/max8821.h
new file mode 100644
index 0000000..80f4c4a
--- /dev/null
+++ b/include/linux/i2c/max8821.h
@@ -0,0 +1,32 @@
+#ifndef __LINUX_MAX8821_H
+#define __LINUX_MAX8821_H
+
+#define MAX8821_LED1 0
+#define MAX8821_LED2 1
+#define MAX8821_LED3 2
+#define MAX8821_LED4 3
+#define MAX8821_LED5 4
+#define MAX8821_LED6 5
+
+#define MAX8821_LDO1 0
+#define MAX8821_LDO2 1
+
+struct max8821_platform_data {
+ struct {
+ char *name;
+ char *trigger; /* see available led triggers */
+ unsigned int brightness; /* use values in [0:31] */
+ } led[6];
+ struct {
+ int power; /* Use 0 or 1 */
+ int voltage; /* see ldo1_voltage[2][] for allowed values */
+ } ldo[2];
+ struct {
+ int power; /* Use 0 or 1 */
+ int clock; /* see write_clock() for allowed values */
+ int gain; /* see write_audio_gain() for allowed values */
+ } audio;
+};
+
+#endif /* __LINUX_MAX8821_H */
+
--
1.5.4.3
More information about the lm-sensors
mailing list