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 26 static struct regmap_config tps6105x_regmap_config = { 27 .reg_bits = 8, 28 .val_bits = 8, 29 .max_register = TPS6105X_REG_3, 30 }; 31 32 static int tps6105x_startup(struct tps6105x *tps6105x) 33 { 34 int ret; 35 unsigned int regval; 36 37 ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val); 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 */ 68 static struct mfd_cell tps6105x_gpio_cell = { 69 .name = "tps6105x-gpio", 70 }; 71 72 static struct mfd_cell tps6105x_leds_cell = { 73 .name = "tps6105x-leds", 74 }; 75 76 static struct mfd_cell tps6105x_flash_cell = { 77 .name = "tps6105x-flash", 78 }; 79 80 static struct mfd_cell tps6105x_regulator_cell = { 81 .name = "tps6105x-regulator", 82 }; 83 84 static 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 94 static 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 154 static 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 168 static const struct i2c_device_id tps6105x_id[] = { 169 { "tps61050", 0 }, 170 { "tps61052", 0 }, 171 { } 172 }; 173 MODULE_DEVICE_TABLE(i2c, tps6105x_id); 174 175 static const struct of_device_id tps6105x_of_match[] = { 176 { .compatible = "ti,tps61050" }, 177 { .compatible = "ti,tps61052" }, 178 { }, 179 }; 180 MODULE_DEVICE_TABLE(of, tps6105x_of_match); 181 182 static 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 192 static int __init tps6105x_init(void) 193 { 194 return i2c_add_driver(&tps6105x_driver); 195 } 196 subsys_initcall(tps6105x_init); 197 198 static void __exit tps6105x_exit(void) 199 { 200 i2c_del_driver(&tps6105x_driver); 201 } 202 module_exit(tps6105x_exit); 203 204 MODULE_AUTHOR("Linus Walleij"); 205 MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver"); 206 MODULE_LICENSE("GPL v2"); 207