tps6105x.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/i2c.h>
  18. #include <linux/mutex.h>
  19. #include <linux/gpio.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/slab.h>
  22. #include <linux/err.h>
  23. #include <linux/regulator/driver.h>
  24. #include <linux/mfd/core.h>
  25. #include <linux/mfd/tps6105x.h>
  26. int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
  27. {
  28. int ret;
  29. ret = mutex_lock_interruptible(&tps6105x->lock);
  30. if (ret)
  31. return ret;
  32. ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
  33. mutex_unlock(&tps6105x->lock);
  34. if (ret < 0)
  35. return ret;
  36. return 0;
  37. }
  38. EXPORT_SYMBOL(tps6105x_set);
  39. int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
  40. {
  41. int ret;
  42. ret = mutex_lock_interruptible(&tps6105x->lock);
  43. if (ret)
  44. return ret;
  45. ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
  46. mutex_unlock(&tps6105x->lock);
  47. if (ret < 0)
  48. return ret;
  49. *buf = ret;
  50. return 0;
  51. }
  52. EXPORT_SYMBOL(tps6105x_get);
  53. /*
  54. * Masks off the bits in the mask and sets the bits in the bitvalues
  55. * parameter in one atomic operation
  56. */
  57. int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
  58. u8 bitmask, u8 bitvalues)
  59. {
  60. int ret;
  61. u8 regval;
  62. ret = mutex_lock_interruptible(&tps6105x->lock);
  63. if (ret)
  64. return ret;
  65. ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
  66. if (ret < 0)
  67. goto fail;
  68. regval = ret;
  69. regval = (~bitmask & regval) | (bitmask & bitvalues);
  70. ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
  71. fail:
  72. mutex_unlock(&tps6105x->lock);
  73. if (ret < 0)
  74. return ret;
  75. return 0;
  76. }
  77. EXPORT_SYMBOL(tps6105x_mask_and_set);
  78. static int __devinit tps6105x_startup(struct tps6105x *tps6105x)
  79. {
  80. int ret;
  81. u8 regval;
  82. ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
  83. if (ret)
  84. return ret;
  85. switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
  86. case TPS6105X_REG0_MODE_SHUTDOWN:
  87. dev_info(&tps6105x->client->dev,
  88. "TPS6105x found in SHUTDOWN mode\n");
  89. break;
  90. case TPS6105X_REG0_MODE_TORCH:
  91. dev_info(&tps6105x->client->dev,
  92. "TPS6105x found in TORCH mode\n");
  93. break;
  94. case TPS6105X_REG0_MODE_TORCH_FLASH:
  95. dev_info(&tps6105x->client->dev,
  96. "TPS6105x found in FLASH mode\n");
  97. break;
  98. case TPS6105X_REG0_MODE_VOLTAGE:
  99. dev_info(&tps6105x->client->dev,
  100. "TPS6105x found in VOLTAGE mode\n");
  101. break;
  102. default:
  103. break;
  104. }
  105. return ret;
  106. }
  107. /*
  108. * MFD cells - we have one cell which is selected operation
  109. * mode, and we always have a GPIO cell.
  110. */
  111. static struct mfd_cell tps6105x_cells[] = {
  112. {
  113. /* name will be runtime assigned */
  114. .id = -1,
  115. },
  116. {
  117. .name = "tps6105x-gpio",
  118. .id = -1,
  119. },
  120. };
  121. static int __devinit tps6105x_probe(struct i2c_client *client,
  122. const struct i2c_device_id *id)
  123. {
  124. struct tps6105x *tps6105x;
  125. struct tps6105x_platform_data *pdata;
  126. int ret;
  127. int i;
  128. tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL);
  129. if (!tps6105x)
  130. return -ENOMEM;
  131. i2c_set_clientdata(client, tps6105x);
  132. tps6105x->client = client;
  133. pdata = client->dev.platform_data;
  134. tps6105x->pdata = pdata;
  135. mutex_init(&tps6105x->lock);
  136. ret = tps6105x_startup(tps6105x);
  137. if (ret) {
  138. dev_err(&client->dev, "chip initialization failed\n");
  139. goto fail;
  140. }
  141. /* Remove warning texts when you implement new cell drivers */
  142. switch (pdata->mode) {
  143. case TPS6105X_MODE_SHUTDOWN:
  144. dev_info(&client->dev,
  145. "present, not used for anything, only GPIO\n");
  146. break;
  147. case TPS6105X_MODE_TORCH:
  148. tps6105x_cells[0].name = "tps6105x-leds";
  149. dev_warn(&client->dev,
  150. "torch mode is unsupported\n");
  151. break;
  152. case TPS6105X_MODE_TORCH_FLASH:
  153. tps6105x_cells[0].name = "tps6105x-flash";
  154. dev_warn(&client->dev,
  155. "flash mode is unsupported\n");
  156. break;
  157. case TPS6105X_MODE_VOLTAGE:
  158. tps6105x_cells[0].name ="tps6105x-regulator";
  159. break;
  160. default:
  161. break;
  162. }
  163. /* Set up and register the platform devices. */
  164. for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
  165. /* One state holder for all drivers, this is simple */
  166. tps6105x_cells[i].platform_data = tps6105x;
  167. tps6105x_cells[i].pdata_size = sizeof(*tps6105x);
  168. }
  169. ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
  170. ARRAY_SIZE(tps6105x_cells), NULL, 0);
  171. if (ret)
  172. goto fail;
  173. return 0;
  174. fail:
  175. kfree(tps6105x);
  176. return ret;
  177. }
  178. static int __devexit tps6105x_remove(struct i2c_client *client)
  179. {
  180. struct tps6105x *tps6105x = i2c_get_clientdata(client);
  181. mfd_remove_devices(&client->dev);
  182. /* Put chip in shutdown mode */
  183. tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
  184. TPS6105X_REG0_MODE_MASK,
  185. TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
  186. kfree(tps6105x);
  187. return 0;
  188. }
  189. static const struct i2c_device_id tps6105x_id[] = {
  190. { "tps61050", 0 },
  191. { "tps61052", 0 },
  192. { }
  193. };
  194. MODULE_DEVICE_TABLE(i2c, tps6105x_id);
  195. static struct i2c_driver tps6105x_driver = {
  196. .driver = {
  197. .name = "tps6105x",
  198. },
  199. .probe = tps6105x_probe,
  200. .remove = __devexit_p(tps6105x_remove),
  201. .id_table = tps6105x_id,
  202. };
  203. static int __init tps6105x_init(void)
  204. {
  205. return i2c_add_driver(&tps6105x_driver);
  206. }
  207. subsys_initcall(tps6105x_init);
  208. static void __exit tps6105x_exit(void)
  209. {
  210. i2c_del_driver(&tps6105x_driver);
  211. }
  212. module_exit(tps6105x_exit);
  213. MODULE_AUTHOR("Linus Walleij");
  214. MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
  215. MODULE_LICENSE("GPL v2");