pm8xxx-upl.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /* Copyright (c) 2010,2011 The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. /*
  14. * Qualcomm PM8XXX UPL driver
  15. *
  16. */
  17. #include <linux/module.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/err.h>
  20. #include <linux/debugfs.h>
  21. #include <linux/slab.h>
  22. #include <linux/mfd/pm8xxx/core.h>
  23. #include <linux/mfd/pm8xxx/upl.h>
  24. /* PMIC8XXX UPL registers */
  25. #define SSBI_REG_UPL_CTRL 0x17B
  26. #define SSBI_REG_UPL_TRUTHTABLE1 0x17C
  27. #define SSBI_REG_UPL_TRUTHTABLE2 0x17D
  28. struct pm8xxx_upl_device {
  29. struct device *dev;
  30. struct mutex upl_mutex;
  31. #if defined(CONFIG_DEBUG_FS)
  32. struct dentry *dent;
  33. #endif
  34. };
  35. static struct pm8xxx_upl_device *upl_dev;
  36. /* APIs */
  37. /*
  38. * pm8xxx_upl_request - request a handle to access UPL device
  39. */
  40. struct pm8xxx_upl_device *pm8xxx_upl_request(void)
  41. {
  42. return upl_dev;
  43. }
  44. EXPORT_SYMBOL(pm8xxx_upl_request);
  45. /*
  46. * pm8xxx_upl_read_truthtable - read value currently stored in UPL truth table
  47. *
  48. * @upldev: the UPL device
  49. * @truthtable: value read from UPL truth table
  50. */
  51. int pm8xxx_upl_read_truthtable(struct pm8xxx_upl_device *upldev,
  52. u16 *truthtable)
  53. {
  54. int rc = 0;
  55. u8 table[2];
  56. if (upldev == NULL || IS_ERR(upldev))
  57. return -EINVAL;
  58. mutex_lock(&upldev->upl_mutex);
  59. rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE1,
  60. &(table[0]));
  61. if (rc) {
  62. pr_err("%s: FAIL pm8xxx_readb(0x%X)=0x%02X: rc=%d\n",
  63. __func__, SSBI_REG_UPL_TRUTHTABLE1, table[0], rc);
  64. goto upl_read_done;
  65. }
  66. rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE2,
  67. &(table[1]));
  68. if (rc)
  69. pr_err("%s: FAIL pm8xxx_readb(0x%X)=0x%02X: rc=%d\n",
  70. __func__, SSBI_REG_UPL_TRUTHTABLE2, table[1], rc);
  71. upl_read_done:
  72. mutex_unlock(&upldev->upl_mutex);
  73. *truthtable = (((u16)table[1]) << 8) | table[0];
  74. return rc;
  75. }
  76. EXPORT_SYMBOL(pm8xxx_upl_read_truthtable);
  77. /*
  78. * pm8xxx_upl_writes_truthtable - write value into UPL truth table
  79. *
  80. * @upldev: the UPL device
  81. * @truthtable: value written to UPL truth table
  82. *
  83. * Each bit in parameter "truthtable" corresponds to the UPL output for a given
  84. * set of input pin values. For example, if the input pins have the following
  85. * values: A=1, B=1, C=1, D=0, then the UPL would output the value of bit 14
  86. * (0b1110) in parameter "truthtable".
  87. */
  88. int pm8xxx_upl_write_truthtable(struct pm8xxx_upl_device *upldev,
  89. u16 truthtable)
  90. {
  91. int rc = 0;
  92. u8 table[2];
  93. if (upldev == NULL || IS_ERR(upldev))
  94. return -EINVAL;
  95. table[0] = truthtable & 0xFF;
  96. table[1] = (truthtable >> 8) & 0xFF;
  97. mutex_lock(&upldev->upl_mutex);
  98. rc = pm8xxx_writeb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE1,
  99. table[0]);
  100. if (rc) {
  101. pr_err("%s: FAIL pm8xxx_writeb(0x%X)=0x%04X: rc=%d\n",
  102. __func__, SSBI_REG_UPL_TRUTHTABLE1, table[0], rc);
  103. goto upl_write_done;
  104. }
  105. rc = pm8xxx_writeb(upldev->dev->parent, SSBI_REG_UPL_TRUTHTABLE2,
  106. table[1]);
  107. if (rc)
  108. pr_err("%s: FAIL pm8xxx_writeb(0x%X)=0x%04X: rc=%d\n",
  109. __func__, SSBI_REG_UPL_TRUTHTABLE2, table[1], rc);
  110. upl_write_done:
  111. mutex_unlock(&upldev->upl_mutex);
  112. return rc;
  113. }
  114. EXPORT_SYMBOL(pm8xxx_upl_write_truthtable);
  115. /*
  116. * pm8xxx_upl_config - configure UPL I/O settings and UPL enable/disable
  117. *
  118. * @upldev: the UPL device
  119. * @mask: setting mask to configure
  120. * @flags: setting flags
  121. */
  122. int pm8xxx_upl_config(struct pm8xxx_upl_device *upldev, u32 mask, u32 flags)
  123. {
  124. int rc;
  125. u8 upl_ctrl, m, f;
  126. if (upldev == NULL || IS_ERR(upldev))
  127. return -EINVAL;
  128. mutex_lock(&upldev->upl_mutex);
  129. rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_CTRL, &upl_ctrl);
  130. if (rc) {
  131. pr_err("%s: FAIL pm8xxx_readb(0x%X)=0x%02X: rc=%d\n",
  132. __func__, SSBI_REG_UPL_CTRL, upl_ctrl, rc);
  133. goto upl_config_done;
  134. }
  135. m = mask & 0x00ff;
  136. f = flags & 0x00ff;
  137. upl_ctrl &= ~m;
  138. upl_ctrl |= m & f;
  139. rc = pm8xxx_writeb(upldev->dev->parent, SSBI_REG_UPL_CTRL, upl_ctrl);
  140. if (rc)
  141. pr_err("%s: FAIL pm8xxx_writeb(0x%X)=0x%02X: rc=%d\n",
  142. __func__, SSBI_REG_UPL_CTRL, upl_ctrl, rc);
  143. upl_config_done:
  144. mutex_unlock(&upldev->upl_mutex);
  145. return rc;
  146. }
  147. EXPORT_SYMBOL(pm8xxx_upl_config);
  148. #if defined(CONFIG_DEBUG_FS)
  149. static int truthtable_set(void *data, u64 val)
  150. {
  151. int rc;
  152. rc = pm8xxx_upl_write_truthtable(data, val);
  153. if (rc)
  154. pr_err("%s: pm8xxx_upl_write_truthtable: rc=%d, "
  155. "truthtable=0x%llX\n", __func__, rc, val);
  156. return rc;
  157. }
  158. static int truthtable_get(void *data, u64 *val)
  159. {
  160. int rc;
  161. u16 truthtable;
  162. rc = pm8xxx_upl_read_truthtable(data, &truthtable);
  163. if (rc)
  164. pr_err("%s: pm8xxx_upl_read_truthtable: rc=%d, "
  165. "truthtable=0x%X\n", __func__, rc, truthtable);
  166. if (val)
  167. *val = truthtable;
  168. return rc;
  169. }
  170. DEFINE_SIMPLE_ATTRIBUTE(upl_truthtable_fops, truthtable_get,
  171. truthtable_set, "0x%04llX\n");
  172. /* enter values as 0xMMMMFFFF where MMMM is the mask and FFFF is the flags */
  173. static int control_set(void *data, u64 val)
  174. {
  175. u8 mask, flags;
  176. int rc;
  177. flags = val & 0xFFFF;
  178. mask = (val >> 16) & 0xFFFF;
  179. rc = pm8xxx_upl_config(data, mask, flags);
  180. if (rc)
  181. pr_err("%s: pm8xxx_upl_config: rc=%d, mask = 0x%X, "
  182. "flags = 0x%X\n", __func__, rc, mask, flags);
  183. return rc;
  184. }
  185. static int control_get(void *data, u64 *val)
  186. {
  187. struct pm8xxx_upl_device *upldev;
  188. int rc = 0;
  189. u8 ctrl;
  190. upldev = data;
  191. mutex_lock(&upldev->upl_mutex);
  192. rc = pm8xxx_readb(upldev->dev->parent, SSBI_REG_UPL_CTRL, &ctrl);
  193. if (rc)
  194. pr_err("%s: FAIL pm8xxx_readb(): rc=%d (ctrl=0x%02X)\n",
  195. __func__, rc, ctrl);
  196. mutex_unlock(&upldev->upl_mutex);
  197. *val = ctrl;
  198. return rc;
  199. }
  200. DEFINE_SIMPLE_ATTRIBUTE(upl_control_fops, control_get,
  201. control_set, "0x%02llX\n");
  202. static int pm8xxx_upl_debug_init(struct pm8xxx_upl_device *upldev)
  203. {
  204. struct dentry *dent;
  205. struct dentry *temp;
  206. dent = debugfs_create_dir("pm8xxx-upl", NULL);
  207. if (dent == NULL || IS_ERR(dent)) {
  208. pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
  209. __func__, (unsigned)dent);
  210. return -ENOMEM;
  211. }
  212. temp = debugfs_create_file("truthtable", S_IRUSR | S_IWUSR, dent,
  213. upldev, &upl_truthtable_fops);
  214. if (temp == NULL || IS_ERR(temp)) {
  215. pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
  216. __func__, (unsigned)dent);
  217. goto debug_error;
  218. }
  219. temp = debugfs_create_file("control", S_IRUSR | S_IWUSR, dent,
  220. upldev, &upl_control_fops);
  221. if (temp == NULL || IS_ERR(temp)) {
  222. pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
  223. __func__, (unsigned)dent);
  224. goto debug_error;
  225. }
  226. upldev->dent = dent;
  227. return 0;
  228. debug_error:
  229. debugfs_remove_recursive(dent);
  230. return -ENOMEM;
  231. }
  232. static int __devexit pm8xxx_upl_debug_remove(struct pm8xxx_upl_device *upldev)
  233. {
  234. debugfs_remove_recursive(upldev->dent);
  235. return 0;
  236. }
  237. #endif /* CONFIG_DEBUG_FS */
  238. static int __devinit pm8xxx_upl_probe(struct platform_device *pdev)
  239. {
  240. struct pm8xxx_upl_device *upldev;
  241. upldev = kzalloc(sizeof *upldev, GFP_KERNEL);
  242. if (upldev == NULL) {
  243. pr_err("%s: kzalloc() failed.\n", __func__);
  244. return -ENOMEM;
  245. }
  246. mutex_init(&upldev->upl_mutex);
  247. upl_dev = upldev;
  248. upldev->dev = &pdev->dev;
  249. platform_set_drvdata(pdev, upldev);
  250. #if defined(CONFIG_DEBUG_FS)
  251. pm8xxx_upl_debug_init(upl_dev);
  252. #endif
  253. pr_notice("%s: OK\n", __func__);
  254. return 0;
  255. }
  256. static int __devexit pm8xxx_upl_remove(struct platform_device *pdev)
  257. {
  258. struct pm8xxx_upl_device *upldev = platform_get_drvdata(pdev);
  259. #if defined(CONFIG_DEBUG_FS)
  260. pm8xxx_upl_debug_remove(upldev);
  261. #endif
  262. platform_set_drvdata(pdev, NULL);
  263. kfree(upldev);
  264. pr_notice("%s: OK\n", __func__);
  265. return 0;
  266. }
  267. static struct platform_driver pm8xxx_upl_driver = {
  268. .probe = pm8xxx_upl_probe,
  269. .remove = __devexit_p(pm8xxx_upl_remove),
  270. .driver = {
  271. .name = PM8XXX_UPL_DEV_NAME,
  272. .owner = THIS_MODULE,
  273. },
  274. };
  275. static int __init pm8xxx_upl_init(void)
  276. {
  277. return platform_driver_register(&pm8xxx_upl_driver);
  278. }
  279. static void __exit pm8xxx_upl_exit(void)
  280. {
  281. platform_driver_unregister(&pm8xxx_upl_driver);
  282. }
  283. module_init(pm8xxx_upl_init);
  284. module_exit(pm8xxx_upl_exit);
  285. MODULE_LICENSE("GPL v2");
  286. MODULE_DESCRIPTION("PM8XXX UPL driver");
  287. MODULE_VERSION("1.0");
  288. MODULE_ALIAS("platform:" PM8XXX_UPL_DEV_NAME);