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/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
  28int 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}
  42EXPORT_SYMBOL(tps6105x_set);
  43
  44int 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}
  59EXPORT_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 */
  65int 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);
  80fail:
  81        mutex_unlock(&tps6105x->lock);
  82        if (ret < 0)
  83                return ret;
  84
  85        return 0;
  86}
  87EXPORT_SYMBOL(tps6105x_mask_and_set);
  88
  89static 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 */
 125static 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
 136static 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].platform_data = tps6105x;
 187                tps6105x_cells[i].pdata_size = sizeof(*tps6105x);
 188        }
 189
 190        ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
 191                              ARRAY_SIZE(tps6105x_cells), NULL, 0, NULL);
 192        if (ret)
 193                goto fail;
 194
 195        return 0;
 196
 197fail:
 198        kfree(tps6105x);
 199        return ret;
 200}
 201
 202static int __devexit tps6105x_remove(struct i2c_client *client)
 203{
 204        struct tps6105x *tps6105x = i2c_get_clientdata(client);
 205
 206        mfd_remove_devices(&client->dev);
 207
 208        /* Put chip in shutdown mode */
 209        tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
 210                TPS6105X_REG0_MODE_MASK,
 211                TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
 212
 213        kfree(tps6105x);
 214        return 0;
 215}
 216
 217static const struct i2c_device_id tps6105x_id[] = {
 218        { "tps61050", 0 },
 219        { "tps61052", 0 },
 220        { }
 221};
 222MODULE_DEVICE_TABLE(i2c, tps6105x_id);
 223
 224static struct i2c_driver tps6105x_driver = {
 225        .driver = {
 226                .name   = "tps6105x",
 227        },
 228        .probe          = tps6105x_probe,
 229        .remove         = __devexit_p(tps6105x_remove),
 230        .id_table       = tps6105x_id,
 231};
 232
 233static int __init tps6105x_init(void)
 234{
 235        return i2c_add_driver(&tps6105x_driver);
 236}
 237subsys_initcall(tps6105x_init);
 238
 239static void __exit tps6105x_exit(void)
 240{
 241        i2c_del_driver(&tps6105x_driver);
 242}
 243module_exit(tps6105x_exit);
 244
 245MODULE_AUTHOR("Linus Walleij");
 246MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
 247MODULE_LICENSE("GPL v2");
 248
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.