tps6586x.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Core driver for TI TPS6586x PMIC family
  3. *
  4. * Copyright (c) 2010 CompuLab Ltd.
  5. * Mike Rapoport <mike@compulab.co.il>
  6. *
  7. * Based on da903x.c.
  8. * Copyright (C) 2008 Compulab, Ltd.
  9. * Mike Rapoport <mike@compulab.co.il>
  10. * Copyright (C) 2006-2008 Marvell International Ltd.
  11. * Eric Miao <eric.miao@marvell.com>
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License version 2 as
  15. * published by the Free Software Foundation.
  16. */
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. #include <linux/mutex.h>
  20. #include <linux/slab.h>
  21. #include <linux/gpio.h>
  22. #include <linux/i2c.h>
  23. #include <linux/mfd/core.h>
  24. #include <linux/mfd/tps6586x.h>
  25. /* GPIO control registers */
  26. #define TPS6586X_GPIOSET1 0x5d
  27. #define TPS6586X_GPIOSET2 0x5e
  28. /* device id */
  29. #define TPS6586X_VERSIONCRC 0xcd
  30. #define TPS658621A_VERSIONCRC 0x15
  31. struct tps6586x {
  32. struct mutex lock;
  33. struct device *dev;
  34. struct i2c_client *client;
  35. struct gpio_chip gpio;
  36. };
  37. static inline int __tps6586x_read(struct i2c_client *client,
  38. int reg, uint8_t *val)
  39. {
  40. int ret;
  41. ret = i2c_smbus_read_byte_data(client, reg);
  42. if (ret < 0) {
  43. dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
  44. return ret;
  45. }
  46. *val = (uint8_t)ret;
  47. return 0;
  48. }
  49. static inline int __tps6586x_reads(struct i2c_client *client, int reg,
  50. int len, uint8_t *val)
  51. {
  52. int ret;
  53. ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
  54. if (ret < 0) {
  55. dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
  56. return ret;
  57. }
  58. return 0;
  59. }
  60. static inline int __tps6586x_write(struct i2c_client *client,
  61. int reg, uint8_t val)
  62. {
  63. int ret;
  64. ret = i2c_smbus_write_byte_data(client, reg, val);
  65. if (ret < 0) {
  66. dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
  67. val, reg);
  68. return ret;
  69. }
  70. return 0;
  71. }
  72. static inline int __tps6586x_writes(struct i2c_client *client, int reg,
  73. int len, uint8_t *val)
  74. {
  75. int ret;
  76. ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
  77. if (ret < 0) {
  78. dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
  79. return ret;
  80. }
  81. return 0;
  82. }
  83. int tps6586x_write(struct device *dev, int reg, uint8_t val)
  84. {
  85. return __tps6586x_write(to_i2c_client(dev), reg, val);
  86. }
  87. EXPORT_SYMBOL_GPL(tps6586x_write);
  88. int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val)
  89. {
  90. return __tps6586x_writes(to_i2c_client(dev), reg, len, val);
  91. }
  92. EXPORT_SYMBOL_GPL(tps6586x_writes);
  93. int tps6586x_read(struct device *dev, int reg, uint8_t *val)
  94. {
  95. return __tps6586x_read(to_i2c_client(dev), reg, val);
  96. }
  97. EXPORT_SYMBOL_GPL(tps6586x_read);
  98. int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val)
  99. {
  100. return __tps6586x_reads(to_i2c_client(dev), reg, len, val);
  101. }
  102. EXPORT_SYMBOL_GPL(tps6586x_reads);
  103. int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
  104. {
  105. struct tps6586x *tps6586x = dev_get_drvdata(dev);
  106. uint8_t reg_val;
  107. int ret = 0;
  108. mutex_lock(&tps6586x->lock);
  109. ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
  110. if (ret)
  111. goto out;
  112. if ((reg_val & bit_mask) == 0) {
  113. reg_val |= bit_mask;
  114. ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
  115. }
  116. out:
  117. mutex_unlock(&tps6586x->lock);
  118. return ret;
  119. }
  120. EXPORT_SYMBOL_GPL(tps6586x_set_bits);
  121. int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
  122. {
  123. struct tps6586x *tps6586x = dev_get_drvdata(dev);
  124. uint8_t reg_val;
  125. int ret = 0;
  126. mutex_lock(&tps6586x->lock);
  127. ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
  128. if (ret)
  129. goto out;
  130. if (reg_val & bit_mask) {
  131. reg_val &= ~bit_mask;
  132. ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
  133. }
  134. out:
  135. mutex_unlock(&tps6586x->lock);
  136. return ret;
  137. }
  138. EXPORT_SYMBOL_GPL(tps6586x_clr_bits);
  139. int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
  140. {
  141. struct tps6586x *tps6586x = dev_get_drvdata(dev);
  142. uint8_t reg_val;
  143. int ret = 0;
  144. mutex_lock(&tps6586x->lock);
  145. ret = __tps6586x_read(tps6586x->client, reg, &reg_val);
  146. if (ret)
  147. goto out;
  148. if ((reg_val & mask) != val) {
  149. reg_val = (reg_val & ~mask) | val;
  150. ret = __tps6586x_write(tps6586x->client, reg, reg_val);
  151. }
  152. out:
  153. mutex_unlock(&tps6586x->lock);
  154. return ret;
  155. }
  156. EXPORT_SYMBOL_GPL(tps6586x_update);
  157. static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
  158. {
  159. struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
  160. uint8_t val;
  161. int ret;
  162. ret = __tps6586x_read(tps6586x->client, TPS6586X_GPIOSET2, &val);
  163. if (ret)
  164. return ret;
  165. return !!(val & (1 << offset));
  166. }
  167. static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
  168. int value)
  169. {
  170. struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
  171. __tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
  172. value << offset);
  173. }
  174. static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
  175. int value)
  176. {
  177. struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
  178. uint8_t val, mask;
  179. tps6586x_gpio_set(gc, offset, value);
  180. val = 0x1 << (offset * 2);
  181. mask = 0x3 << (offset * 2);
  182. return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
  183. }
  184. static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
  185. {
  186. int ret;
  187. if (!gpio_base)
  188. return;
  189. tps6586x->gpio.owner = THIS_MODULE;
  190. tps6586x->gpio.label = tps6586x->client->name;
  191. tps6586x->gpio.dev = tps6586x->dev;
  192. tps6586x->gpio.base = gpio_base;
  193. tps6586x->gpio.ngpio = 4;
  194. tps6586x->gpio.can_sleep = 1;
  195. /* FIXME: add handling of GPIOs as dedicated inputs */
  196. tps6586x->gpio.direction_output = tps6586x_gpio_output;
  197. tps6586x->gpio.set = tps6586x_gpio_set;
  198. tps6586x->gpio.get = tps6586x_gpio_get;
  199. ret = gpiochip_add(&tps6586x->gpio);
  200. if (ret)
  201. dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret);
  202. }
  203. static int __remove_subdev(struct device *dev, void *unused)
  204. {
  205. platform_device_unregister(to_platform_device(dev));
  206. return 0;
  207. }
  208. static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
  209. {
  210. return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
  211. }
  212. static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
  213. struct tps6586x_platform_data *pdata)
  214. {
  215. struct tps6586x_subdev_info *subdev;
  216. struct platform_device *pdev;
  217. int i, ret = 0;
  218. for (i = 0; i < pdata->num_subdevs; i++) {
  219. subdev = &pdata->subdevs[i];
  220. pdev = platform_device_alloc(subdev->name, subdev->id);
  221. pdev->dev.parent = tps6586x->dev;
  222. pdev->dev.platform_data = subdev->platform_data;
  223. ret = platform_device_add(pdev);
  224. if (ret)
  225. goto failed;
  226. }
  227. return 0;
  228. failed:
  229. tps6586x_remove_subdevs(tps6586x);
  230. return ret;
  231. }
  232. static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
  233. const struct i2c_device_id *id)
  234. {
  235. struct tps6586x_platform_data *pdata = client->dev.platform_data;
  236. struct tps6586x *tps6586x;
  237. int ret;
  238. if (!pdata) {
  239. dev_err(&client->dev, "tps6586x requires platform data\n");
  240. return -ENOTSUPP;
  241. }
  242. ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC);
  243. if (ret < 0) {
  244. dev_err(&client->dev, "Chip ID read failed: %d\n", ret);
  245. return -EIO;
  246. }
  247. if (ret != TPS658621A_VERSIONCRC) {
  248. dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
  249. return -ENODEV;
  250. }
  251. tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
  252. if (tps6586x == NULL)
  253. return -ENOMEM;
  254. tps6586x->client = client;
  255. tps6586x->dev = &client->dev;
  256. i2c_set_clientdata(client, tps6586x);
  257. mutex_init(&tps6586x->lock);
  258. ret = tps6586x_add_subdevs(tps6586x, pdata);
  259. if (ret) {
  260. dev_err(&client->dev, "add devices failed: %d\n", ret);
  261. goto err_add_devs;
  262. }
  263. tps6586x_gpio_init(tps6586x, pdata->gpio_base);
  264. return 0;
  265. err_add_devs:
  266. kfree(tps6586x);
  267. return ret;
  268. }
  269. static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
  270. {
  271. return 0;
  272. }
  273. static const struct i2c_device_id tps6586x_id_table[] = {
  274. { "tps6586x", 0 },
  275. { },
  276. };
  277. MODULE_DEVICE_TABLE(i2c, tps6586x_id_table);
  278. static struct i2c_driver tps6586x_driver = {
  279. .driver = {
  280. .name = "tps6586x",
  281. .owner = THIS_MODULE,
  282. },
  283. .probe = tps6586x_i2c_probe,
  284. .remove = __devexit_p(tps6586x_i2c_remove),
  285. .id_table = tps6586x_id_table,
  286. };
  287. static int __init tps6586x_init(void)
  288. {
  289. return i2c_add_driver(&tps6586x_driver);
  290. }
  291. subsys_initcall(tps6586x_init);
  292. static void __exit tps6586x_exit(void)
  293. {
  294. i2c_del_driver(&tps6586x_driver);
  295. }
  296. module_exit(tps6586x_exit);
  297. MODULE_DESCRIPTION("TPS6586X core driver");
  298. MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
  299. MODULE_LICENSE("GPL");