linux/drivers/mfd/tps6105x.c
<<
>>
Prefs
   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/regmap.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
  28static struct regmap_config tps6105x_regmap_config = {
  29        .reg_bits = 8,
  30        .val_bits = 8,
  31        .max_register = TPS6105X_REG_3,
  32};
  33
  34static int tps6105x_startup(struct tps6105x *tps6105x)
  35{
  36        int ret;
  37        unsigned int regval;
  38
  39        ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
  40        if (ret)
  41                return ret;
  42        switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
  43        case TPS6105X_REG0_MODE_SHUTDOWN:
  44                dev_info(&tps6105x->client->dev,
  45                         "TPS6105x found in SHUTDOWN mode\n");
  46                break;
  47        case TPS6105X_REG0_MODE_TORCH:
  48                dev_info(&tps6105x->client->dev,
  49                         "TPS6105x found in TORCH mode\n");
  50                break;
  51        case TPS6105X_REG0_MODE_TORCH_FLASH:
  52                dev_info(&tps6105x->client->dev,
  53                         "TPS6105x found in FLASH mode\n");
  54                break;
  55        case TPS6105X_REG0_MODE_VOLTAGE:
  56                dev_info(&tps6105x->client->dev,
  57                         "TPS6105x found in VOLTAGE mode\n");
  58                break;
  59        default:
  60                break;
  61        }
  62
  63        return ret;
  64}
  65
  66/*
  67 * MFD cells - we always have a GPIO cell and we have one cell
  68 * which is selected operation mode.
  69 */
  70static struct mfd_cell tps6105x_gpio_cell = {
  71        .name = "tps6105x-gpio",
  72};
  73
  74static struct mfd_cell tps6105x_leds_cell = {
  75        .name = "tps6105x-leds",
  76};
  77
  78static struct mfd_cell tps6105x_flash_cell = {
  79        .name = "tps6105x-flash",
  80};
  81
  82static struct mfd_cell tps6105x_regulator_cell = {
  83        .name = "tps6105x-regulator",
  84};
  85
  86static int tps6105x_add_device(struct tps6105x *tps6105x,
  87                               struct mfd_cell *cell)
  88{
  89        cell->platform_data = tps6105x;
  90        cell->pdata_size = sizeof(*tps6105x);
  91
  92        return mfd_add_devices(&tps6105x->client->dev,
  93                               PLATFORM_DEVID_AUTO, cell, 1, NULL, 0, NULL);
  94}
  95
  96static int tps6105x_probe(struct i2c_client *client,
  97                        const struct i2c_device_id *id)
  98{
  99        struct tps6105x                 *tps6105x;
 100        struct tps6105x_platform_data   *pdata;
 101        int ret;
 102
 103        pdata = dev_get_platdata(&client->dev);
 104        if (!pdata) {
 105                dev_err(&client->dev, "missing platform data\n");
 106                return -ENODEV;
 107        }
 108
 109        tps6105x = devm_kmalloc(&client->dev, sizeof(*tps6105x), GFP_KERNEL);
 110        if (!tps6105x)
 111                return -ENOMEM;
 112
 113        tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config);
 114        if (IS_ERR(tps6105x->regmap))
 115                return PTR_ERR(tps6105x->regmap);
 116
 117        i2c_set_clientdata(client, tps6105x);
 118        tps6105x->client = client;
 119        tps6105x->pdata = pdata;
 120
 121        ret = tps6105x_startup(tps6105x);
 122        if (ret) {
 123                dev_err(&client->dev, "chip initialization failed\n");
 124                return ret;
 125        }
 126
 127        ret = tps6105x_add_device(tps6105x, &tps6105x_gpio_cell);
 128        if (ret)
 129                return ret;
 130
 131        switch (pdata->mode) {
 132        case TPS6105X_MODE_SHUTDOWN:
 133                dev_info(&client->dev,
 134                         "present, not used for anything, only GPIO\n");
 135                break;
 136        case TPS6105X_MODE_TORCH:
 137                ret = tps6105x_add_device(tps6105x, &tps6105x_leds_cell);
 138                break;
 139        case TPS6105X_MODE_TORCH_FLASH:
 140                ret = tps6105x_add_device(tps6105x, &tps6105x_flash_cell);
 141                break;
 142        case TPS6105X_MODE_VOLTAGE:
 143                ret = tps6105x_add_device(tps6105x, &tps6105x_regulator_cell);
 144                break;
 145        default:
 146                dev_warn(&client->dev, "invalid mode: %d\n", pdata->mode);
 147                break;
 148        }
 149
 150        if (ret)
 151                mfd_remove_devices(&client->dev);
 152
 153        return ret;
 154}
 155
 156static int tps6105x_remove(struct i2c_client *client)
 157{
 158        struct tps6105x *tps6105x = i2c_get_clientdata(client);
 159
 160        mfd_remove_devices(&client->dev);
 161
 162        /* Put chip in shutdown mode */
 163        regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
 164                TPS6105X_REG0_MODE_MASK,
 165                TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
 166
 167        return 0;
 168}
 169
 170static const struct i2c_device_id tps6105x_id[] = {
 171        { "tps61050", 0 },
 172        { "tps61052", 0 },
 173        { }
 174};
 175MODULE_DEVICE_TABLE(i2c, tps6105x_id);
 176
 177static struct i2c_driver tps6105x_driver = {
 178        .driver = {
 179                .name   = "tps6105x",
 180        },
 181        .probe          = tps6105x_probe,
 182        .remove         = tps6105x_remove,
 183        .id_table       = tps6105x_id,
 184};
 185
 186static int __init tps6105x_init(void)
 187{
 188        return i2c_add_driver(&tps6105x_driver);
 189}
 190subsys_initcall(tps6105x_init);
 191
 192static void __exit tps6105x_exit(void)
 193{
 194        i2c_del_driver(&tps6105x_driver);
 195}
 196module_exit(tps6105x_exit);
 197
 198MODULE_AUTHOR("Linus Walleij");
 199MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
 200MODULE_LICENSE("GPL v2");
 201