linux/drivers/mfd/tps6105x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Core driver for TPS61050/61052 boost converters, used for while LED
   4 * driving, audio power amplification, white LED flash, and generic
   5 * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in)
   6 * and a flash synchronization pin to synchronize flash events when used as
   7 * flashgun.
   8 *
   9 * Copyright (C) 2011 ST-Ericsson SA
  10 * Written on behalf of Linaro for ST-Ericsson
  11 *
  12 * Author: Linus Walleij <linus.walleij@linaro.org>
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/i2c.h>
  18#include <linux/regmap.h>
  19#include <linux/gpio.h>
  20#include <linux/spinlock.h>
  21#include <linux/slab.h>
  22#include <linux/err.h>
  23#include <linux/mfd/core.h>
  24#include <linux/mfd/tps6105x.h>
  25
  26static struct regmap_config tps6105x_regmap_config = {
  27        .reg_bits = 8,
  28        .val_bits = 8,
  29        .max_register = TPS6105X_REG_3,
  30};
  31
  32static int tps6105x_startup(struct tps6105x *tps6105x)
  33{
  34        int ret;
  35        unsigned int regval;
  36
  37        ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
  38        if (ret)
  39                return ret;
  40        switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
  41        case TPS6105X_REG0_MODE_SHUTDOWN:
  42                dev_info(&tps6105x->client->dev,
  43                         "TPS6105x found in SHUTDOWN mode\n");
  44                break;
  45        case TPS6105X_REG0_MODE_TORCH:
  46                dev_info(&tps6105x->client->dev,
  47                         "TPS6105x found in TORCH mode\n");
  48                break;
  49        case TPS6105X_REG0_MODE_TORCH_FLASH:
  50                dev_info(&tps6105x->client->dev,
  51                         "TPS6105x found in FLASH mode\n");
  52                break;
  53        case TPS6105X_REG0_MODE_VOLTAGE:
  54                dev_info(&tps6105x->client->dev,
  55                         "TPS6105x found in VOLTAGE mode\n");
  56                break;
  57        default:
  58                break;
  59        }
  60
  61        return ret;
  62}
  63
  64/*
  65 * MFD cells - we always have a GPIO cell and we have one cell
  66 * which is selected operation mode.
  67 */
  68static struct mfd_cell tps6105x_gpio_cell = {
  69        .name = "tps6105x-gpio",
  70};
  71
  72static struct mfd_cell tps6105x_leds_cell = {
  73        .name = "tps6105x-leds",
  74};
  75
  76static struct mfd_cell tps6105x_flash_cell = {
  77        .name = "tps6105x-flash",
  78};
  79
  80static struct mfd_cell tps6105x_regulator_cell = {
  81        .name = "tps6105x-regulator",
  82};
  83
  84static int tps6105x_add_device(struct tps6105x *tps6105x,
  85                               struct mfd_cell *cell)
  86{
  87        cell->platform_data = tps6105x;
  88        cell->pdata_size = sizeof(*tps6105x);
  89
  90        return mfd_add_devices(&tps6105x->client->dev,
  91                               PLATFORM_DEVID_AUTO, cell, 1, NULL, 0, NULL);
  92}
  93
  94static int tps6105x_probe(struct i2c_client *client,
  95                        const struct i2c_device_id *id)
  96{
  97        struct tps6105x                 *tps6105x;
  98        struct tps6105x_platform_data   *pdata;
  99        int ret;
 100
 101        pdata = dev_get_platdata(&client->dev);
 102        if (!pdata) {
 103                dev_err(&client->dev, "missing platform data\n");
 104                return -ENODEV;
 105        }
 106
 107        tps6105x = devm_kmalloc(&client->dev, sizeof(*tps6105x), GFP_KERNEL);
 108        if (!tps6105x)
 109                return -ENOMEM;
 110
 111        tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config);
 112        if (IS_ERR(tps6105x->regmap))
 113                return PTR_ERR(tps6105x->regmap);
 114
 115        i2c_set_clientdata(client, tps6105x);
 116        tps6105x->client = client;
 117        tps6105x->pdata = pdata;
 118
 119        ret = tps6105x_startup(tps6105x);
 120        if (ret) {
 121                dev_err(&client->dev, "chip initialization failed\n");
 122                return ret;
 123        }
 124
 125        ret = tps6105x_add_device(tps6105x, &tps6105x_gpio_cell);
 126        if (ret)
 127                return ret;
 128
 129        switch (pdata->mode) {
 130        case TPS6105X_MODE_SHUTDOWN:
 131                dev_info(&client->dev,
 132                         "present, not used for anything, only GPIO\n");
 133                break;
 134        case TPS6105X_MODE_TORCH:
 135                ret = tps6105x_add_device(tps6105x, &tps6105x_leds_cell);
 136                break;
 137        case TPS6105X_MODE_TORCH_FLASH:
 138                ret = tps6105x_add_device(tps6105x, &tps6105x_flash_cell);
 139                break;
 140        case TPS6105X_MODE_VOLTAGE:
 141                ret = tps6105x_add_device(tps6105x, &tps6105x_regulator_cell);
 142                break;
 143        default:
 144                dev_warn(&client->dev, "invalid mode: %d\n", pdata->mode);
 145                break;
 146        }
 147
 148        if (ret)
 149                mfd_remove_devices(&client->dev);
 150
 151        return ret;
 152}
 153
 154static int tps6105x_remove(struct i2c_client *client)
 155{
 156        struct tps6105x *tps6105x = i2c_get_clientdata(client);
 157
 158        mfd_remove_devices(&client->dev);
 159
 160        /* Put chip in shutdown mode */
 161        regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
 162                TPS6105X_REG0_MODE_MASK,
 163                TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
 164
 165        return 0;
 166}
 167
 168static const struct i2c_device_id tps6105x_id[] = {
 169        { "tps61050", 0 },
 170        { "tps61052", 0 },
 171        { }
 172};
 173MODULE_DEVICE_TABLE(i2c, tps6105x_id);
 174
 175static const struct of_device_id tps6105x_of_match[] = {
 176        { .compatible = "ti,tps61050" },
 177        { .compatible = "ti,tps61052" },
 178        { },
 179};
 180MODULE_DEVICE_TABLE(of, tps6105x_of_match);
 181
 182static struct i2c_driver tps6105x_driver = {
 183        .driver = {
 184                .name   = "tps6105x",
 185                .of_match_table = tps6105x_of_match,
 186        },
 187        .probe          = tps6105x_probe,
 188        .remove         = tps6105x_remove,
 189        .id_table       = tps6105x_id,
 190};
 191
 192static int __init tps6105x_init(void)
 193{
 194        return i2c_add_driver(&tps6105x_driver);
 195}
 196subsys_initcall(tps6105x_init);
 197
 198static void __exit tps6105x_exit(void)
 199{
 200        i2c_del_driver(&tps6105x_driver);
 201}
 202module_exit(tps6105x_exit);
 203
 204MODULE_AUTHOR("Linus Walleij");
 205MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
 206MODULE_LICENSE("GPL v2");
 207