Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Core driver for TPS61050/61052 boost converters, used for while LED
0004  * driving, audio power amplification, white LED flash, and generic
0005  * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in)
0006  * and a flash synchronization pin to synchronize flash events when used as
0007  * flashgun.
0008  *
0009  * Copyright (C) 2011 ST-Ericsson SA
0010  * Written on behalf of Linaro for ST-Ericsson
0011  *
0012  * Author: Linus Walleij <linus.walleij@linaro.org>
0013  */
0014 
0015 #include <linux/module.h>
0016 #include <linux/init.h>
0017 #include <linux/i2c.h>
0018 #include <linux/regmap.h>
0019 #include <linux/gpio.h>
0020 #include <linux/spinlock.h>
0021 #include <linux/slab.h>
0022 #include <linux/err.h>
0023 #include <linux/mfd/core.h>
0024 #include <linux/mfd/tps6105x.h>
0025 
0026 static struct regmap_config tps6105x_regmap_config = {
0027     .reg_bits = 8,
0028     .val_bits = 8,
0029     .max_register = TPS6105X_REG_3,
0030 };
0031 
0032 static int tps6105x_startup(struct tps6105x *tps6105x)
0033 {
0034     int ret;
0035     unsigned int regval;
0036 
0037     ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
0038     if (ret)
0039         return ret;
0040     switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
0041     case TPS6105X_REG0_MODE_SHUTDOWN:
0042         dev_info(&tps6105x->client->dev,
0043              "TPS6105x found in SHUTDOWN mode\n");
0044         break;
0045     case TPS6105X_REG0_MODE_TORCH:
0046         dev_info(&tps6105x->client->dev,
0047              "TPS6105x found in TORCH mode\n");
0048         break;
0049     case TPS6105X_REG0_MODE_TORCH_FLASH:
0050         dev_info(&tps6105x->client->dev,
0051              "TPS6105x found in FLASH mode\n");
0052         break;
0053     case TPS6105X_REG0_MODE_VOLTAGE:
0054         dev_info(&tps6105x->client->dev,
0055              "TPS6105x found in VOLTAGE mode\n");
0056         break;
0057     default:
0058         break;
0059     }
0060 
0061     return ret;
0062 }
0063 
0064 /*
0065  * MFD cells - we always have a GPIO cell and we have one cell
0066  * which is selected operation mode.
0067  */
0068 static struct mfd_cell tps6105x_gpio_cell = {
0069     .name = "tps6105x-gpio",
0070 };
0071 
0072 static struct mfd_cell tps6105x_leds_cell = {
0073     .name = "tps6105x-leds",
0074 };
0075 
0076 static struct mfd_cell tps6105x_flash_cell = {
0077     .name = "tps6105x-flash",
0078 };
0079 
0080 static struct mfd_cell tps6105x_regulator_cell = {
0081     .name = "tps6105x-regulator",
0082 };
0083 
0084 static int tps6105x_add_device(struct tps6105x *tps6105x,
0085                    struct mfd_cell *cell)
0086 {
0087     cell->platform_data = tps6105x;
0088     cell->pdata_size = sizeof(*tps6105x);
0089 
0090     return mfd_add_devices(&tps6105x->client->dev,
0091                    PLATFORM_DEVID_AUTO, cell, 1, NULL, 0, NULL);
0092 }
0093 
0094 static struct tps6105x_platform_data *tps6105x_parse_dt(struct device *dev)
0095 {
0096     struct device_node *np = dev->of_node;
0097     struct tps6105x_platform_data *pdata;
0098     struct device_node *child;
0099 
0100     if (!np)
0101         return ERR_PTR(-EINVAL);
0102     if (of_get_available_child_count(np) > 1) {
0103         dev_err(dev, "cannot support multiple operational modes");
0104         return ERR_PTR(-EINVAL);
0105     }
0106     pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
0107     if (!pdata)
0108         return ERR_PTR(-ENOMEM);
0109     pdata->mode = TPS6105X_MODE_SHUTDOWN;
0110     for_each_available_child_of_node(np, child) {
0111         if (child->name && !of_node_cmp(child->name, "regulator"))
0112             pdata->mode = TPS6105X_MODE_VOLTAGE;
0113         else if (child->name && !of_node_cmp(child->name, "led"))
0114             pdata->mode = TPS6105X_MODE_TORCH;
0115     }
0116 
0117     return pdata;
0118 }
0119 
0120 static int tps6105x_probe(struct i2c_client *client,
0121             const struct i2c_device_id *id)
0122 {
0123     struct tps6105x         *tps6105x;
0124     struct tps6105x_platform_data   *pdata;
0125     int ret;
0126 
0127     pdata = dev_get_platdata(&client->dev);
0128     if (!pdata)
0129         pdata = tps6105x_parse_dt(&client->dev);
0130     if (IS_ERR(pdata)) {
0131         dev_err(&client->dev, "No platform data or DT found");
0132         return PTR_ERR(pdata);
0133     }
0134 
0135     tps6105x = devm_kmalloc(&client->dev, sizeof(*tps6105x), GFP_KERNEL);
0136     if (!tps6105x)
0137         return -ENOMEM;
0138 
0139     tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config);
0140     if (IS_ERR(tps6105x->regmap))
0141         return PTR_ERR(tps6105x->regmap);
0142 
0143     i2c_set_clientdata(client, tps6105x);
0144     tps6105x->client = client;
0145     tps6105x->pdata = pdata;
0146 
0147     ret = tps6105x_startup(tps6105x);
0148     if (ret) {
0149         dev_err(&client->dev, "chip initialization failed\n");
0150         return ret;
0151     }
0152 
0153     ret = tps6105x_add_device(tps6105x, &tps6105x_gpio_cell);
0154     if (ret)
0155         return ret;
0156 
0157     switch (pdata->mode) {
0158     case TPS6105X_MODE_SHUTDOWN:
0159         dev_info(&client->dev,
0160              "present, not used for anything, only GPIO\n");
0161         break;
0162     case TPS6105X_MODE_TORCH:
0163         ret = tps6105x_add_device(tps6105x, &tps6105x_leds_cell);
0164         break;
0165     case TPS6105X_MODE_TORCH_FLASH:
0166         ret = tps6105x_add_device(tps6105x, &tps6105x_flash_cell);
0167         break;
0168     case TPS6105X_MODE_VOLTAGE:
0169         ret = tps6105x_add_device(tps6105x, &tps6105x_regulator_cell);
0170         break;
0171     default:
0172         dev_warn(&client->dev, "invalid mode: %d\n", pdata->mode);
0173         break;
0174     }
0175 
0176     if (ret)
0177         mfd_remove_devices(&client->dev);
0178 
0179     return ret;
0180 }
0181 
0182 static int tps6105x_remove(struct i2c_client *client)
0183 {
0184     struct tps6105x *tps6105x = i2c_get_clientdata(client);
0185 
0186     mfd_remove_devices(&client->dev);
0187 
0188     /* Put chip in shutdown mode */
0189     regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
0190         TPS6105X_REG0_MODE_MASK,
0191         TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
0192 
0193     return 0;
0194 }
0195 
0196 static const struct i2c_device_id tps6105x_id[] = {
0197     { "tps61050", 0 },
0198     { "tps61052", 0 },
0199     { }
0200 };
0201 MODULE_DEVICE_TABLE(i2c, tps6105x_id);
0202 
0203 static const struct of_device_id tps6105x_of_match[] = {
0204     { .compatible = "ti,tps61050" },
0205     { .compatible = "ti,tps61052" },
0206     { },
0207 };
0208 MODULE_DEVICE_TABLE(of, tps6105x_of_match);
0209 
0210 static struct i2c_driver tps6105x_driver = {
0211     .driver = {
0212         .name   = "tps6105x",
0213         .of_match_table = tps6105x_of_match,
0214     },
0215     .probe      = tps6105x_probe,
0216     .remove     = tps6105x_remove,
0217     .id_table   = tps6105x_id,
0218 };
0219 
0220 static int __init tps6105x_init(void)
0221 {
0222     return i2c_add_driver(&tps6105x_driver);
0223 }
0224 subsys_initcall(tps6105x_init);
0225 
0226 static void __exit tps6105x_exit(void)
0227 {
0228     i2c_del_driver(&tps6105x_driver);
0229 }
0230 module_exit(tps6105x_exit);
0231 
0232 MODULE_AUTHOR("Linus Walleij");
0233 MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
0234 MODULE_LICENSE("GPL v2");