From patchwork Tue Mar 8 09:40:41 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 419 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:42:34 -0000 Delivered-To: patches@linaro.org Received: by 10.224.60.68 with SMTP id o4cs21750qah; Tue, 8 Mar 2011 01:41:58 -0800 (PST) Received: by 10.213.21.209 with SMTP id k17mr2546393ebb.50.1299577317744; Tue, 08 Mar 2011 01:41:57 -0800 (PST) Received: from eu1sys200aog106.obsmtp.com (eu1sys200aog106.obsmtp.com [207.126.144.121]) by mx.google.com with SMTP id q18si1164282eeh.20.2011.03.08.01.41.49 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 08 Mar 2011 01:41:57 -0800 (PST) Received-SPF: neutral (google.com: 207.126.144.121 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.121; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.121 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) smtp.mail=linus.walleij@stericsson.com Received: from source ([164.129.1.35]) (using TLSv1) by eu1sys200aob106.postini.com ([207.126.147.11]) with SMTP ID DSNKTXX53N6qkyn5LoODywTFask46D2n+1ZX@postini.com; Tue, 08 Mar 2011 09:41:57 UTC Received: from zeta.dmz-eu.st.com (ns2.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 97641262; Tue, 8 Mar 2011 09:41:20 +0000 (GMT) Received: from relay1.stm.gmessaging.net (unknown [10.230.100.17]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 370811B70; Tue, 8 Mar 2011 09:41:20 +0000 (GMT) Received: from exdcvycastm003.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm003", Issuer "exdcvycastm003" (not verified)) by relay1.stm.gmessaging.net (Postfix) with ESMTPS id 0A58F24C2C0; Tue, 8 Mar 2011 10:40:45 +0100 (CET) Received: from localhost.localdomain (10.230.100.153) by smtp.stericsson.com (10.230.100.1) with Microsoft SMTP Server (TLS) id 8.2.254.0; Tue, 8 Mar 2011 10:40:49 +0100 From: Linus Walleij To: Samuel Ortiz , Cc: Lee Jones , Linus Walleij , Liam Girdwood , Mark Brown , Ola Lilja Subject: [PATCH 1/3] mfd: add a core driver for TI TPS61050/TPS61052 chips Date: Tue, 8 Mar 2011 10:40:41 +0100 Message-ID: <1299577241-31328-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.3.2 MIME-Version: 1.0 From: Linus Walleij The TPS61050/TPS61052 are boost converters, LED drivers, LED flash drivers and a simple GPIO pin chips. Cc: Liam Girdwood Cc: Mark Brown Cc: Ola Lilja Signed-off-by: Linus Walleij --- drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 1 + drivers/mfd/tps6105x.c | 251 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/tps6105x.h | 101 +++++++++++++++++ 4 files changed, 365 insertions(+), 0 deletions(-) create mode 100644 drivers/mfd/tps6105x.c create mode 100644 include/linux/mfd/tps6105x.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fd01836..cb61262 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -118,6 +118,18 @@ config UCB1400_CORE To compile this driver as a module, choose M here: the module will be called ucb1400_core. +config TPS6105X + tristate "TPS61050/61052 Boost Converters" + depends on I2C && EXPERIMENTAL + select REGULATOR + select REGULATOR_FIXED_VOLTAGE + default y if MACH_U8500 + help + This option enables a driver for the TP61050/TPS61052 + high-power "white LED driver". This boost converter is + sometimes used for other things than white LEDs, and + also contains a GPIO pin. + config TPS65010 tristate "TPS6501x Power Management chips" depends on I2C && GPIOLIB diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a54e2c7..6eb8372 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o +obj-$(CONFIG_TPS6105X) += tps6105x.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS6507X) += tps6507x.o obj-$(CONFIG_MENELAUS) += menelaus.o diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c new file mode 100644 index 0000000..24f4043 --- /dev/null +++ b/drivers/mfd/tps6105x.c @@ -0,0 +1,251 @@ +/* + * Core driver for TPS61050/61052 boost converters, used for while LED + * driving, audio power amplification, white LED flash, and generic + * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in) + * and a flash synchronization pin to synchronize flash events when used as + * flashgun. + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro + * + * Author: Linus Walleij for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value) +{ + int ret; + + ret = mutex_lock_interruptible(&tps6105x->lock); + if (ret) + return ret; + ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value); + mutex_unlock(&tps6105x->lock); + if (ret < 0) + return ret; + + return 0; +} + +int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf) +{ + int ret; + + ret = mutex_lock_interruptible(&tps6105x->lock); + if (ret) + return ret; + ret = i2c_smbus_read_byte_data(tps6105x->client, reg); + mutex_unlock(&tps6105x->lock); + if (ret < 0) + return ret; + + *buf = ret; + return 0; +} + +/* + * Masks off the bits in the mask and sets the bits in the bitvalues + * parameter in one atomic operation + */ +int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, + u8 bitmask, u8 bitvalues) +{ + int ret; + u8 regval; + + ret = mutex_lock_interruptible(&tps6105x->lock); + if (ret) + return ret; + ret = i2c_smbus_read_byte_data(tps6105x->client, reg); + if (ret < 0) + goto fail; + regval = ret; + regval = (~bitmask & regval) | (bitmask & bitvalues); + ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval); +fail: + mutex_unlock(&tps6105x->lock); + if (ret < 0) + return ret; + + return 0; +} + + +static int __devinit tps6105x_startup(struct tps6105x *tps6105x) +{ + int ret; + u8 regval; + + ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + if (ret) + return ret; + switch (regval >> TPS6105X_REG0_MODE_SHIFT) { + case TPS6105X_REG0_MODE_SHUTDOWN: + dev_info(&tps6105x->client->dev, + "TPS6105x found in SHUTDOWN mode\n"); + break; + case TPS6105X_REG0_MODE_TORCH: + dev_info(&tps6105x->client->dev, + "TPS6105x found in TORCH mode\n"); + break; + case TPS6105X_REG0_MODE_TORCH_FLASH: + dev_info(&tps6105x->client->dev, + "TPS6105x found in FLASH mode\n"); + break; + case TPS6105X_REG0_MODE_VOLTAGE: + dev_info(&tps6105x->client->dev, + "TPS6105x found in VOLTAGE mode\n"); + break; + default: + break; + } + + /* Put the chip in SHUTDOWN mode */ + ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + TPS6105X_REG0_MODE_MASK, + TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); + if (ret) + return ret; + + return 0; +} + +/* MFD cells for subdevices */ +static struct mfd_cell tps6105x_cells[] = { + { + .name = "tps6105x-regulator", + .id = -1, + }, + { + .name = "tps6105x-leds", + .id = -1, + }, + { + .name = "tps6105x-flash", + .id = -1, + }, + { + .name = "tps6105x-gpio", + .id = -1, + }, +}; + +static int __devinit tps6105x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps6105x *tps6105x; + struct tps6105x_platform_data *pdata; + int ret; + int i; + + tps6105x = kzalloc(sizeof(*tps6105x), GFP_KERNEL); + if (!tps6105x) + return -ENOMEM; + + i2c_set_clientdata(client, tps6105x); + tps6105x->client = client; + pdata = client->dev.platform_data; + tps6105x->pdata = pdata; + mutex_init(&tps6105x->lock); + + ret = tps6105x_startup(tps6105x); + if (ret) { + dev_err(&client->dev, "chip initialization failed\n"); + goto fail; + } + + /* Set up and register the platform devices. */ + for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) { + /* One state holder for all drivers, this is simple */ + tps6105x_cells[i].driver_data = tps6105x; + } + + ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, + ARRAY_SIZE(tps6105x_cells), NULL, 0); + if (ret) + goto fail; + + /* Remove warning texts when you implement new cell drivers */ + switch (pdata->mode) { + case TPS6105X_MODE_SHUTDOWN: + dev_info(&client->dev, + "present, not used for anything\n"); + break; + case TPS6105X_MODE_TORCH: + dev_warn(&client->dev, + "torch mode is unsupported\n"); + break; + case TPS6105X_MODE_TORCH_FLASH: + dev_warn(&client->dev, + "flash mode is unsupported\n"); + break; + case TPS6105X_MODE_VOLTAGE: + default: + break; + } + return 0; + +fail: + i2c_set_clientdata(client, NULL); + kfree(tps6105x); + return ret; +} + +static int __devexit tps6105x_remove(struct i2c_client *client) +{ + struct tps6105x *tps6105x = i2c_get_clientdata(client); + + /* Put chip in shutdown mode */ + tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + TPS6105X_REG0_MODE_MASK, + TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); + + kfree(tps6105x); + return 0; +} + +static const struct i2c_device_id tps6105x_id[] = { + { "tps61050", 0 }, + { "tps61052", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tps6105x_id); + +static struct i2c_driver tps6105x_driver = { + .driver = { + .name = "tps6105x", + }, + .probe = tps6105x_probe, + .remove = __devexit_p(tps6105x_remove), + .id_table = tps6105x_id, +}; + +static int __init tps6105x_init(void) +{ + return i2c_add_driver(&tps6105x_driver); +} + +static void __exit tps6105x_exit(void) +{ + i2c_del_driver(&tps6105x_driver); +} + +subsys_initcall(tps6105x_init); +module_exit(tps6105x_exit); + +MODULE_AUTHOR("Linus Walleij"); +MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/tps6105x.h b/include/linux/mfd/tps6105x.h new file mode 100644 index 0000000..884c28d --- /dev/null +++ b/include/linux/mfd/tps6105x.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro + * + * Author: Linus Walleij for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef MFD_TPS6105X_H +#define MFD_TPS6105X_H + +#include +#include + +/* + * Register definitions to all subdrivers + */ +#define TPS6105X_REG_0 (0x00) +#define TPS6105X_REG0_MODE_SHIFT (6) +#define TPS6105X_REG0_MODE_MASK (0x03<<6) +/* These defines for both reg0 and reg1 */ +#define TPS6105X_REG0_MODE_SHUTDOWN (0x00) +#define TPS6105X_REG0_MODE_TORCH (0x01) +#define TPS6105X_REG0_MODE_TORCH_FLASH (0x02) +#define TPS6105X_REG0_MODE_VOLTAGE (0x03) +#define TPS6105X_REG0_VOLTAGE_SHIFT (4) +#define TPS6105X_REG0_VOLTAGE_MASK (3<<4) +#define TPS6105X_REG0_VOLTAGE_450 (0) +#define TPS6105X_REG0_VOLTAGE_500 (1) +#define TPS6105X_REG0_VOLTAGE_525 (2) +#define TPS6105X_REG0_VOLTAGE_500_2 (3) +#define TPS6105X_REG0_DIMMING_SHIFT (3) +#define TPS6105X_REG0_TORCHC_SHIFT (0) +#define TPS6105X_REG0_TORCHC_MASK (7<<0) +#define TPS6105X_REG0_TORCHC_0 (0x00) +#define TPS6105X_REG0_TORCHC_50 (0x01) +#define TPS6105X_REG0_TORCHC_75 (0x02) +#define TPS6105X_REG0_TORCHC_100 (0x03) +#define TPS6105X_REG0_TORCHC_150 (0x04) +#define TPS6105X_REG0_TORCHC_200 (0x05) +#define TPS6105X_REG0_TORCHC_250_400 (0x06) +#define TPS6105X_REG0_TORCHC_250_500 (0x07) +#define TPS6105X_REG_1 (0x01) +#define TPS6105X_REG1_MODE_SHIFT (6) +#define TPS6105X_REG1_MODE_MASK (0x03<<6) +#define TPS6105X_REG1_MODE_SHUTDOWN (0x00) +#define TPS6105X_REG1_MODE_TORCH (0x01) +#define TPS6105X_REG1_MODE_TORCH_FLASH (0x02) +#define TPS6105X_REG1_MODE_VOLTAGE (0x03) +#define TPS6105X_REG_2 (0x02) +#define TPS6105X_REG_3 (0x03) + +/** + * enum tps6105x_mode - desired mode for the TPS6105x + * @TPS6105X_MODE_SHUTDOWN: this instance is inactive, not used for anything + * @TPS61905X_MODE_TORCH: this instance is used as a LED, usually a while + * LED, for example as backlight or flashlight. If this is set, the + * TPS6105X will register to the LED framework + * @TPS6105X_MODE_TORCH_FLASH: this instance is used as a flashgun, usually + * in a camera + * @TPS6105X_MODE_VOLTAGE: this instance is used as a voltage regulator and + * will register to the regulator framework + */ +enum tps6105x_mode { + TPS6105X_MODE_SHUTDOWN, + TPS6105X_MODE_TORCH, + TPS6105X_MODE_TORCH_FLASH, + TPS6105X_MODE_VOLTAGE, +}; + +/** + * struct tps6105x_platform_data - TPS61905x platform data + * @mode: what mode this instance shall be operated in, + * this is not selectable at runtime + * @regulator_data: initialization data for the voltage + * regulator if used as a voltage source + */ +struct tps6105x_platform_data { + enum tps6105x_mode mode; + struct regulator_init_data *regulator_data; +}; + +/** + * struct tps6105x - state holder for the TPS6105x drivers + * @mutex: mutex to serialize I2C accesses + * @i2c_client: corresponding I2C client + * @regulator: regulator device if used in voltage mode + */ +struct tps6105x { + struct tps6105x_platform_data *pdata; + struct mutex lock; + struct i2c_client *client; + struct regulator_dev *regulator; +}; + +extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value); +extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf); +extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, + u8 bitmask, u8 bitvalues); + +#endif