Commit 798a8eee44da56b4f2e000ff81dfb49d09c65b71

Authored by Linus Walleij
Committed by Samuel Ortiz
1 parent f04ddfcd24

mfd: Add a core driver for TI TPS61050/TPS61052 chips v2

The TPS61050/TPS61052 are boost converters, LED drivers, LED flash
drivers and a simple GPIO pin chips.

Cc: Liam Girdwood <lrg@slimlogic.co.uk>
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Jonas Aberg <jonas.aberg@stericsson.com>
Cc: Ola Lilja <ola.o.lilja@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

Showing 4 changed files with 351 additions and 0 deletions Side-by-side Diff

... ... @@ -129,6 +129,15 @@
129 129 To compile this driver as a module, choose M here: the
130 130 module will be called ucb1400_core.
131 131  
  132 +config TPS6105X
  133 + tristate "TPS61050/61052 Boost Converters"
  134 + depends on I2C
  135 + help
  136 + This option enables a driver for the TP61050/TPS61052
  137 + high-power "white LED driver". This boost converter is
  138 + sometimes used for other things than white LEDs, and
  139 + also contains a GPIO pin.
  140 +
132 141 config TPS65010
133 142 tristate "TPS6501x Power Management chips"
134 143 depends on I2C && GPIOLIB
drivers/mfd/Makefile
... ... @@ -33,6 +33,7 @@
33 33 obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
34 34 obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
35 35  
  36 +obj-$(CONFIG_TPS6105X) += tps6105x.o
36 37 obj-$(CONFIG_TPS65010) += tps65010.o
37 38 obj-$(CONFIG_TPS6507X) += tps6507x.o
38 39 obj-$(CONFIG_MENELAUS) += menelaus.o
drivers/mfd/tps6105x.c
  1 +/*
  2 + * Core driver for TPS61050/61052 boost converters, used for while LED
  3 + * driving, audio power amplification, white LED flash, and generic
  4 + * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in)
  5 + * and a flash synchronization pin to synchronize flash events when used as
  6 + * flashgun.
  7 + *
  8 + * Copyright (C) 2011 ST-Ericsson SA
  9 + * Written on behalf of Linaro for ST-Ericsson
  10 + *
  11 + * Author: Linus Walleij <linus.walleij@linaro.org>
  12 + *
  13 + * License terms: GNU General Public License (GPL) version 2
  14 + */
  15 +
  16 +#include <linux/module.h>
  17 +#include <linux/init.h>
  18 +#include <linux/i2c.h>
  19 +#include <linux/mutex.h>
  20 +#include <linux/gpio.h>
  21 +#include <linux/spinlock.h>
  22 +#include <linux/slab.h>
  23 +#include <linux/err.h>
  24 +#include <linux/regulator/driver.h>
  25 +#include <linux/mfd/core.h>
  26 +#include <linux/mfd/tps6105x.h>
  27 +
  28 +int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
  29 +{
  30 + int ret;
  31 +
  32 + ret = mutex_lock_interruptible(&tps6105x->lock);
  33 + if (ret)
  34 + return ret;
  35 + ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
  36 + mutex_unlock(&tps6105x->lock);
  37 + if (ret < 0)
  38 + return ret;
  39 +
  40 + return 0;
  41 +}
  42 +EXPORT_SYMBOL(tps6105x_set);
  43 +
  44 +int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
  45 +{
  46 + int ret;
  47 +
  48 + ret = mutex_lock_interruptible(&tps6105x->lock);
  49 + if (ret)
  50 + return ret;
  51 + ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
  52 + mutex_unlock(&tps6105x->lock);
  53 + if (ret < 0)
  54 + return ret;
  55 +
  56 + *buf = ret;
  57 + return 0;
  58 +}
  59 +EXPORT_SYMBOL(tps6105x_get);
  60 +
  61 +/*
  62 + * Masks off the bits in the mask and sets the bits in the bitvalues
  63 + * parameter in one atomic operation
  64 + */
  65 +int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
  66 + u8 bitmask, u8 bitvalues)
  67 +{
  68 + int ret;
  69 + u8 regval;
  70 +
  71 + ret = mutex_lock_interruptible(&tps6105x->lock);
  72 + if (ret)
  73 + return ret;
  74 + ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
  75 + if (ret < 0)
  76 + goto fail;
  77 + regval = ret;
  78 + regval = (~bitmask & regval) | (bitmask & bitvalues);
  79 + ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
  80 +fail:
  81 + mutex_unlock(&tps6105x->lock);
  82 + if (ret < 0)
  83 + return ret;
  84 +
  85 + return 0;
  86 +}
  87 +EXPORT_SYMBOL(tps6105x_mask_and_set);
  88 +
  89 +static int __devinit tps6105x_startup(struct tps6105x *tps6105x)
  90 +{
  91 + int ret;
  92 + u8 regval;
  93 +
  94 + ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
  95 + if (ret)
  96 + return ret;
  97 + switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
  98 + case TPS6105X_REG0_MODE_SHUTDOWN:
  99 + dev_info(&tps6105x->client->dev,
  100 + "TPS6105x found in SHUTDOWN mode\n");
  101 + break;
  102 + case TPS6105X_REG0_MODE_TORCH:
  103 + dev_info(&tps6105x->client->dev,
  104 + "TPS6105x found in TORCH mode\n");
  105 + break;
  106 + case TPS6105X_REG0_MODE_TORCH_FLASH:
  107 + dev_info(&tps6105x->client->dev,
  108 + "TPS6105x found in FLASH mode\n");
  109 + break;
  110 + case TPS6105X_REG0_MODE_VOLTAGE:
  111 + dev_info(&tps6105x->client->dev,
  112 + "TPS6105x found in VOLTAGE mode\n");
  113 + break;
  114 + default:
  115 + break;
  116 + }
  117 +
  118 + return ret;
  119 +}
  120 +
  121 +/*
  122 + * MFD cells - we have one cell which is selected operation
  123 + * mode, and we always have a GPIO cell.
  124 + */
  125 +static struct mfd_cell tps6105x_cells[] = {
  126 + {
  127 + /* name will be runtime assigned */
  128 + .id = -1,
  129 + },
  130 + {
  131 + .name = "tps6105x-gpio",
  132 + .id = -1,
  133 + },
  134 +};
  135 +
  136 +static int __devinit tps6105x_probe(struct i2c_client *client,
  137 + const struct i2c_device_id *id)
  138 +{
  139 + struct tps6105x *tps6105x;
  140 + struct tps6105x_platform_data *pdata;
  141 + int ret;
  142 + int i;
  143 +
  144 + tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL);
  145 + if (!tps6105x)
  146 + return -ENOMEM;
  147 +
  148 + i2c_set_clientdata(client, tps6105x);
  149 + tps6105x->client = client;
  150 + pdata = client->dev.platform_data;
  151 + tps6105x->pdata = pdata;
  152 + mutex_init(&tps6105x->lock);
  153 +
  154 + ret = tps6105x_startup(tps6105x);
  155 + if (ret) {
  156 + dev_err(&client->dev, "chip initialization failed\n");
  157 + goto fail;
  158 + }
  159 +
  160 + /* Remove warning texts when you implement new cell drivers */
  161 + switch (pdata->mode) {
  162 + case TPS6105X_MODE_SHUTDOWN:
  163 + dev_info(&client->dev,
  164 + "present, not used for anything, only GPIO\n");
  165 + break;
  166 + case TPS6105X_MODE_TORCH:
  167 + tps6105x_cells[0].name = "tps6105x-leds";
  168 + dev_warn(&client->dev,
  169 + "torch mode is unsupported\n");
  170 + break;
  171 + case TPS6105X_MODE_TORCH_FLASH:
  172 + tps6105x_cells[0].name = "tps6105x-flash";
  173 + dev_warn(&client->dev,
  174 + "flash mode is unsupported\n");
  175 + break;
  176 + case TPS6105X_MODE_VOLTAGE:
  177 + tps6105x_cells[0].name ="tps6105x-regulator";
  178 + break;
  179 + default:
  180 + break;
  181 + }
  182 +
  183 + /* Set up and register the platform devices. */
  184 + for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
  185 + /* One state holder for all drivers, this is simple */
  186 + tps6105x_cells[i].mfd_data = tps6105x;
  187 + }
  188 +
  189 + ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
  190 + ARRAY_SIZE(tps6105x_cells), NULL, 0);
  191 + if (ret)
  192 + goto fail;
  193 +
  194 + return 0;
  195 +
  196 +fail:
  197 + kfree(tps6105x);
  198 + return ret;
  199 +}
  200 +
  201 +static int __devexit tps6105x_remove(struct i2c_client *client)
  202 +{
  203 + struct tps6105x *tps6105x = i2c_get_clientdata(client);
  204 +
  205 + mfd_remove_devices(&client->dev);
  206 +
  207 + /* Put chip in shutdown mode */
  208 + tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
  209 + TPS6105X_REG0_MODE_MASK,
  210 + TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
  211 +
  212 + kfree(tps6105x);
  213 + return 0;
  214 +}
  215 +
  216 +static const struct i2c_device_id tps6105x_id[] = {
  217 + { "tps61050", 0 },
  218 + { "tps61052", 0 },
  219 + { }
  220 +};
  221 +MODULE_DEVICE_TABLE(i2c, tps6105x_id);
  222 +
  223 +static struct i2c_driver tps6105x_driver = {
  224 + .driver = {
  225 + .name = "tps6105x",
  226 + },
  227 + .probe = tps6105x_probe,
  228 + .remove = __devexit_p(tps6105x_remove),
  229 + .id_table = tps6105x_id,
  230 +};
  231 +
  232 +static int __init tps6105x_init(void)
  233 +{
  234 + return i2c_add_driver(&tps6105x_driver);
  235 +}
  236 +subsys_initcall(tps6105x_init);
  237 +
  238 +static void __exit tps6105x_exit(void)
  239 +{
  240 + i2c_del_driver(&tps6105x_driver);
  241 +}
  242 +module_exit(tps6105x_exit);
  243 +
  244 +MODULE_AUTHOR("Linus Walleij");
  245 +MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
  246 +MODULE_LICENSE("GPL v2");
include/linux/mfd/tps6105x.h
  1 +/*
  2 + * Copyright (C) 2011 ST-Ericsson SA
  3 + * Written on behalf of Linaro for ST-Ericsson
  4 + *
  5 + * Author: Linus Walleij <linus.walleij@linaro.org>
  6 + *
  7 + * License terms: GNU General Public License (GPL) version 2
  8 + */
  9 +#ifndef MFD_TPS6105X_H
  10 +#define MFD_TPS6105X_H
  11 +
  12 +#include <linux/i2c.h>
  13 +
  14 +/*
  15 + * Register definitions to all subdrivers
  16 + */
  17 +#define TPS6105X_REG_0 0x00
  18 +#define TPS6105X_REG0_MODE_SHIFT 6
  19 +#define TPS6105X_REG0_MODE_MASK (0x03<<6)
  20 +/* These defines for both reg0 and reg1 */
  21 +#define TPS6105X_REG0_MODE_SHUTDOWN 0x00
  22 +#define TPS6105X_REG0_MODE_TORCH 0x01
  23 +#define TPS6105X_REG0_MODE_TORCH_FLASH 0x02
  24 +#define TPS6105X_REG0_MODE_VOLTAGE 0x03
  25 +#define TPS6105X_REG0_VOLTAGE_SHIFT 4
  26 +#define TPS6105X_REG0_VOLTAGE_MASK (3<<4)
  27 +#define TPS6105X_REG0_VOLTAGE_450 0
  28 +#define TPS6105X_REG0_VOLTAGE_500 1
  29 +#define TPS6105X_REG0_VOLTAGE_525 2
  30 +#define TPS6105X_REG0_VOLTAGE_500_2 3
  31 +#define TPS6105X_REG0_DIMMING_SHIFT 3
  32 +#define TPS6105X_REG0_TORCHC_SHIFT 0
  33 +#define TPS6105X_REG0_TORCHC_MASK (7<<0)
  34 +#define TPS6105X_REG0_TORCHC_0 0x00
  35 +#define TPS6105X_REG0_TORCHC_50 0x01
  36 +#define TPS6105X_REG0_TORCHC_75 0x02
  37 +#define TPS6105X_REG0_TORCHC_100 0x03
  38 +#define TPS6105X_REG0_TORCHC_150 0x04
  39 +#define TPS6105X_REG0_TORCHC_200 0x05
  40 +#define TPS6105X_REG0_TORCHC_250_400 0x06
  41 +#define TPS6105X_REG0_TORCHC_250_500 0x07
  42 +#define TPS6105X_REG_1 0x01
  43 +#define TPS6105X_REG1_MODE_SHIFT 6
  44 +#define TPS6105X_REG1_MODE_MASK (0x03<<6)
  45 +#define TPS6105X_REG1_MODE_SHUTDOWN 0x00
  46 +#define TPS6105X_REG1_MODE_TORCH 0x01
  47 +#define TPS6105X_REG1_MODE_TORCH_FLASH 0x02
  48 +#define TPS6105X_REG1_MODE_VOLTAGE 0x03
  49 +#define TPS6105X_REG_2 0x02
  50 +#define TPS6105X_REG_3 0x03
  51 +
  52 +/**
  53 + * enum tps6105x_mode - desired mode for the TPS6105x
  54 + * @TPS6105X_MODE_SHUTDOWN: this instance is inactive, not used for anything
  55 + * @TPS61905X_MODE_TORCH: this instance is used as a LED, usually a while
  56 + * LED, for example as backlight or flashlight. If this is set, the
  57 + * TPS6105X will register to the LED framework
  58 + * @TPS6105X_MODE_TORCH_FLASH: this instance is used as a flashgun, usually
  59 + * in a camera
  60 + * @TPS6105X_MODE_VOLTAGE: this instance is used as a voltage regulator and
  61 + * will register to the regulator framework
  62 + */
  63 +enum tps6105x_mode {
  64 + TPS6105X_MODE_SHUTDOWN,
  65 + TPS6105X_MODE_TORCH,
  66 + TPS6105X_MODE_TORCH_FLASH,
  67 + TPS6105X_MODE_VOLTAGE,
  68 +};
  69 +
  70 +/**
  71 + * struct tps6105x_platform_data - TPS61905x platform data
  72 + * @mode: what mode this instance shall be operated in,
  73 + * this is not selectable at runtime
  74 + */
  75 +struct tps6105x_platform_data {
  76 + enum tps6105x_mode mode;
  77 +};
  78 +
  79 +/**
  80 + * struct tps6105x - state holder for the TPS6105x drivers
  81 + * @mutex: mutex to serialize I2C accesses
  82 + * @i2c_client: corresponding I2C client
  83 + */
  84 +struct tps6105x {
  85 + struct tps6105x_platform_data *pdata;
  86 + struct mutex lock;
  87 + struct i2c_client *client;
  88 +};
  89 +
  90 +extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value);
  91 +extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf);
  92 +extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
  93 + u8 bitmask, u8 bitvalues);
  94 +
  95 +#endif