mdss_io_util.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /* Copyright (c) 2012-2013, 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. #include <linux/clk.h>
  13. #include <linux/err.h>
  14. #include <linux/io.h>
  15. #include <linux/delay.h>
  16. #include "mdss_io_util.h"
  17. #define MAX_I2C_CMDS 16
  18. void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
  19. {
  20. u32 in_val;
  21. if (!io || !io->base) {
  22. DEV_ERR("%pS->%s: invalid input\n",
  23. __builtin_return_address(0), __func__);
  24. return;
  25. }
  26. if (offset > io->len) {
  27. DEV_ERR("%pS->%s: offset out of range\n",
  28. __builtin_return_address(0), __func__);
  29. return;
  30. }
  31. writel_relaxed(value, io->base + offset);
  32. if (debug) {
  33. in_val = readl_relaxed(io->base + offset);
  34. DEV_DBG("[%08x] => %08x [%08x]\n", (u32)(io->base + offset),
  35. value, in_val);
  36. }
  37. } /* dss_reg_w */
  38. u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug)
  39. {
  40. u32 value;
  41. if (!io || !io->base) {
  42. DEV_ERR("%pS->%s: invalid input\n",
  43. __builtin_return_address(0), __func__);
  44. return -EINVAL;
  45. }
  46. if (offset > io->len) {
  47. DEV_ERR("%pS->%s: offset out of range\n",
  48. __builtin_return_address(0), __func__);
  49. return -EINVAL;
  50. }
  51. value = readl_relaxed(io->base + offset);
  52. if (debug)
  53. DEV_DBG("[%08x] <= %08x\n", (u32)(io->base + offset), value);
  54. return value;
  55. } /* dss_reg_r */
  56. void dss_reg_dump(void __iomem *base, u32 length, const char *prefix,
  57. u32 debug)
  58. {
  59. if (debug)
  60. print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
  61. (void *)base, length, false);
  62. } /* dss_reg_dump */
  63. static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
  64. unsigned int type, const char *name)
  65. {
  66. struct resource *res = NULL;
  67. res = platform_get_resource_byname(pdev, type, name);
  68. if (!res)
  69. DEV_ERR("%s: '%s' resource not found\n", __func__, name);
  70. return res;
  71. } /* msm_dss_get_res_byname */
  72. int msm_dss_ioremap_byname(struct platform_device *pdev,
  73. struct dss_io_data *io_data, const char *name)
  74. {
  75. struct resource *res = NULL;
  76. if (!pdev || !io_data) {
  77. DEV_ERR("%pS->%s: invalid input\n",
  78. __builtin_return_address(0), __func__);
  79. return -EINVAL;
  80. }
  81. res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
  82. if (!res) {
  83. DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n",
  84. __builtin_return_address(0), __func__, name);
  85. return -ENODEV;
  86. }
  87. io_data->len = resource_size(res);
  88. io_data->base = ioremap(res->start, io_data->len);
  89. if (!io_data->base) {
  90. DEV_ERR("%pS->%s: '%s' ioremap failed\n",
  91. __builtin_return_address(0), __func__, name);
  92. return -EIO;
  93. }
  94. return 0;
  95. } /* msm_dss_ioremap_byname */
  96. void msm_dss_iounmap(struct dss_io_data *io_data)
  97. {
  98. if (!io_data) {
  99. DEV_ERR("%pS->%s: invalid input\n",
  100. __builtin_return_address(0), __func__);
  101. return;
  102. }
  103. if (io_data->base) {
  104. iounmap(io_data->base);
  105. io_data->base = NULL;
  106. }
  107. io_data->len = 0;
  108. } /* msm_dss_iounmap */
  109. int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
  110. int num_vreg, int config)
  111. {
  112. int i = 0, rc = 0;
  113. struct dss_vreg *curr_vreg = NULL;
  114. enum dss_vreg_type type;
  115. if (config) {
  116. for (i = 0; i < num_vreg; i++) {
  117. curr_vreg = &in_vreg[i];
  118. curr_vreg->vreg = regulator_get(dev,
  119. curr_vreg->vreg_name);
  120. rc = PTR_RET(curr_vreg->vreg);
  121. if (rc) {
  122. DEV_ERR("%pS->%s: %s get failed. rc=%d\n",
  123. __builtin_return_address(0), __func__,
  124. curr_vreg->vreg_name, rc);
  125. curr_vreg->vreg = NULL;
  126. goto vreg_get_fail;
  127. }
  128. #ifdef CONFIG_FB_MSM_MIPI_MAGNA_OCTA_VIDEO_WXGA_PT_DUAL_PANEL
  129. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4)) {
  130. pr_err("%s : VDD(L22) config(%d) skip!!\n", __func__, config);
  131. continue;
  132. }
  133. #endif
  134. type = (regulator_count_voltages(curr_vreg->vreg) > 0)
  135. ? DSS_REG_LDO : DSS_REG_VS;
  136. if (type == DSS_REG_LDO) {
  137. rc = regulator_set_voltage(
  138. curr_vreg->vreg,
  139. curr_vreg->min_voltage,
  140. curr_vreg->max_voltage);
  141. if (rc < 0) {
  142. DEV_ERR("%pS->%s: %s set vltg fail\n",
  143. __builtin_return_address(0),
  144. __func__,
  145. curr_vreg->vreg_name);
  146. goto vreg_set_voltage_fail;
  147. }
  148. }
  149. }
  150. } else {
  151. for (i = num_vreg-1; i >= 0; i--) {
  152. curr_vreg = &in_vreg[i];
  153. #ifdef CONFIG_FB_MSM_MIPI_MAGNA_OCTA_VIDEO_WXGA_PT_DUAL_PANEL
  154. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4)) {
  155. pr_err("%s : VDD(L22) config(%d) skip!!\n", __func__, config);
  156. continue;
  157. }
  158. #endif
  159. if (curr_vreg->vreg) {
  160. type = (regulator_count_voltages(
  161. curr_vreg->vreg) > 0)
  162. ? DSS_REG_LDO : DSS_REG_VS;
  163. if (type == DSS_REG_LDO) {
  164. regulator_set_voltage(curr_vreg->vreg,
  165. 0, curr_vreg->max_voltage);
  166. }
  167. regulator_put(curr_vreg->vreg);
  168. curr_vreg->vreg = NULL;
  169. }
  170. }
  171. }
  172. return 0;
  173. vreg_unconfig:
  174. if (type == DSS_REG_LDO)
  175. regulator_set_optimum_mode(curr_vreg->vreg, 0);
  176. vreg_set_voltage_fail:
  177. regulator_put(curr_vreg->vreg);
  178. curr_vreg->vreg = NULL;
  179. vreg_get_fail:
  180. for (i--; i >= 0; i--) {
  181. curr_vreg = &in_vreg[i];
  182. type = (regulator_count_voltages(curr_vreg->vreg) > 0)
  183. ? DSS_REG_LDO : DSS_REG_VS;
  184. goto vreg_unconfig;
  185. }
  186. return rc;
  187. } /* msm_dss_config_vreg */
  188. #ifdef CONFIG_MACH_KSPORTSLTE_SPR
  189. extern unsigned int system_rev;
  190. #endif
  191. int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
  192. {
  193. int i = 0, rc = 0;
  194. if (enable) {
  195. for (i = 0; i < num_vreg; i++) {
  196. #if defined(CONFIG_MACH_MONDRIAN) || defined(CONFIG_MACH_CHAGALL)
  197. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4)) {
  198. pr_info("%s : VDD enable skip!!\n", __func__);
  199. continue;
  200. }
  201. #endif
  202. #ifdef CONFIG_MACH_KSPORTSLTE_SPR
  203. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4) && (system_rev == 2)) {
  204. pr_info("%s : VDD enable skip!! rev(%d)\n",in_vreg[i].vreg_name, system_rev);
  205. continue;
  206. }
  207. #endif
  208. #ifdef CONFIG_FB_MSM_MIPI_MAGNA_OCTA_VIDEO_WXGA_PT_DUAL_PANEL
  209. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4)) {
  210. pr_err("%s : VDD enable skip!!\n", __func__);
  211. continue;
  212. }
  213. #endif
  214. rc = PTR_RET(in_vreg[i].vreg);
  215. if (rc) {
  216. DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
  217. __builtin_return_address(0), __func__,
  218. in_vreg[i].vreg_name, rc);
  219. goto vreg_set_opt_mode_fail;
  220. }
  221. if (in_vreg[i].pre_on_sleep)
  222. usleep_range(in_vreg[i].pre_on_sleep * 1000,
  223. in_vreg[i].pre_on_sleep * 1000);
  224. rc = regulator_set_optimum_mode(in_vreg[i].vreg,
  225. in_vreg[i].enable_load);
  226. if (rc < 0) {
  227. DEV_ERR("%pS->%s: %s set opt m fail\n",
  228. __builtin_return_address(0), __func__,
  229. in_vreg[i].vreg_name);
  230. goto vreg_set_opt_mode_fail;
  231. }
  232. rc = regulator_enable(in_vreg[i].vreg);
  233. if (in_vreg[i].post_on_sleep)
  234. usleep_range(in_vreg[i].post_on_sleep * 1000,
  235. in_vreg[i].post_on_sleep * 1000);
  236. if (rc < 0) {
  237. DEV_ERR("%pS->%s: %s enable failed\n",
  238. __builtin_return_address(0), __func__,
  239. in_vreg[i].vreg_name);
  240. goto disable_vreg;
  241. }
  242. }
  243. } else {
  244. for (i = num_vreg-1; i >= 0; i--)
  245. if (regulator_is_enabled(in_vreg[i].vreg)) {
  246. #if defined(CONFIG_MACH_MONDRIAN) || defined(CONFIG_MACH_CHAGALL)
  247. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4)) {
  248. pr_info("%s : VDD disable skip!!\n", __func__);
  249. continue;
  250. }
  251. #endif
  252. #ifdef CONFIG_MACH_KANAS3G_CTC
  253. if(!strncmp(in_vreg[i].vreg_name, "vdd", 3)) {
  254. continue;
  255. }
  256. #endif
  257. #ifdef CONFIG_MACH_KSPORTSLTE_SPR
  258. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4) && (system_rev == 2)) {
  259. pr_info("%s : VDD disable skip!! rev(%d)\n",in_vreg[i].vreg_name, system_rev);
  260. continue;
  261. }
  262. #endif
  263. #ifdef CONFIG_FB_MSM_MIPI_MAGNA_OCTA_VIDEO_WXGA_PT_DUAL_PANEL
  264. if(!strncmp(in_vreg[i].vreg_name, "vdd", 4)) {
  265. pr_err("%s : VDD disable skip!!\n", __func__);
  266. continue;
  267. }
  268. #endif
  269. #ifdef CONFIG_MACH_KLIMT_LTE_DCM
  270. /* VREG_LVS1_1P8 Always On due to Audio(MP3) Play Mute Problem */
  271. if(!strncmp(in_vreg[i].vreg_name, "vdd3", 4)) { // VREG_LVS1_1P8 1.8V
  272. pr_err("%s : VDD3 disable skip!!\n", __func__);
  273. continue;
  274. }
  275. #endif
  276. if (in_vreg[i].pre_off_sleep)
  277. usleep_range(
  278. in_vreg[i].pre_off_sleep * 1000,
  279. in_vreg[i].pre_off_sleep * 1000);
  280. regulator_set_optimum_mode(in_vreg[i].vreg,
  281. in_vreg[i].disable_load);
  282. regulator_disable(in_vreg[i].vreg);
  283. if (in_vreg[i].post_off_sleep)
  284. usleep_range(
  285. in_vreg[i].post_off_sleep * 1000,
  286. in_vreg[i].post_off_sleep * 1000);
  287. }
  288. }
  289. return rc;
  290. disable_vreg:
  291. regulator_set_optimum_mode(in_vreg[i].vreg, in_vreg[i].disable_load);
  292. vreg_set_opt_mode_fail:
  293. for (i--; i >= 0; i--) {
  294. if (in_vreg[i].pre_off_sleep)
  295. msleep(in_vreg[i].pre_off_sleep);
  296. regulator_set_optimum_mode(in_vreg[i].vreg,
  297. in_vreg[i].disable_load);
  298. regulator_disable(in_vreg[i].vreg);
  299. if (in_vreg[i].post_off_sleep)
  300. msleep(in_vreg[i].post_off_sleep);
  301. }
  302. return rc;
  303. } /* msm_dss_enable_vreg */
  304. int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable)
  305. {
  306. int i = 0, rc = 0;
  307. if (enable) {
  308. for (i = 0; i < num_gpio; i++) {
  309. DEV_DBG("%pS->%s: %s enable\n",
  310. __builtin_return_address(0), __func__,
  311. in_gpio[i].gpio_name);
  312. rc = gpio_request(in_gpio[i].gpio,
  313. in_gpio[i].gpio_name);
  314. if (rc < 0) {
  315. DEV_ERR("%pS->%s: %s enable failed\n",
  316. __builtin_return_address(0), __func__,
  317. in_gpio[i].gpio_name);
  318. goto disable_gpio;
  319. }
  320. gpio_set_value(in_gpio[i].gpio, in_gpio[i].value);
  321. }
  322. } else {
  323. for (i = num_gpio-1; i >= 0; i--) {
  324. DEV_DBG("%pS->%s: %s disable\n",
  325. __builtin_return_address(0), __func__,
  326. in_gpio[i].gpio_name);
  327. if (in_gpio[i].gpio)
  328. gpio_free(in_gpio[i].gpio);
  329. }
  330. }
  331. return rc;
  332. disable_gpio:
  333. for (i--; i >= 0; i--)
  334. if (in_gpio[i].gpio)
  335. gpio_free(in_gpio[i].gpio);
  336. return rc;
  337. } /* msm_dss_enable_gpio */
  338. void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
  339. {
  340. int i;
  341. for (i = num_clk - 1; i >= 0; i--) {
  342. if (clk_arry[i].clk)
  343. clk_put(clk_arry[i].clk);
  344. clk_arry[i].clk = NULL;
  345. }
  346. } /* msm_dss_put_clk */
  347. int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
  348. {
  349. int i, rc = 0;
  350. for (i = 0; i < num_clk; i++) {
  351. clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
  352. rc = PTR_RET(clk_arry[i].clk);
  353. if (rc) {
  354. DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
  355. __builtin_return_address(0), __func__,
  356. clk_arry[i].clk_name, rc);
  357. goto error;
  358. }
  359. }
  360. return rc;
  361. error:
  362. msm_dss_put_clk(clk_arry, num_clk);
  363. return rc;
  364. } /* msm_dss_get_clk */
  365. int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
  366. {
  367. int i, rc = 0;
  368. for (i = 0; i < num_clk; i++) {
  369. if (clk_arry[i].clk) {
  370. if (DSS_CLK_AHB != clk_arry[i].type) {
  371. DEV_DBG("%pS->%s: '%s' rate %ld\n",
  372. __builtin_return_address(0), __func__,
  373. clk_arry[i].clk_name,
  374. clk_arry[i].rate);
  375. rc = clk_set_rate(clk_arry[i].clk,
  376. clk_arry[i].rate);
  377. if (rc) {
  378. DEV_ERR("%pS->%s: %s failed. rc=%d\n",
  379. __builtin_return_address(0),
  380. __func__,
  381. clk_arry[i].clk_name, rc);
  382. break;
  383. }
  384. }
  385. } else {
  386. DEV_ERR("%pS->%s: '%s' is not available\n",
  387. __builtin_return_address(0), __func__,
  388. clk_arry[i].clk_name);
  389. rc = -EPERM;
  390. break;
  391. }
  392. }
  393. return rc;
  394. } /* msm_dss_clk_set_rate */
  395. int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
  396. {
  397. int i, rc = 0;
  398. if (enable) {
  399. for (i = 0; i < num_clk; i++) {
  400. DEV_DBG("%pS->%s: enable '%s'\n",
  401. __builtin_return_address(0), __func__,
  402. clk_arry[i].clk_name);
  403. if (clk_arry[i].clk) {
  404. rc = clk_prepare_enable(clk_arry[i].clk);
  405. if (rc)
  406. DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
  407. __builtin_return_address(0),
  408. __func__,
  409. clk_arry[i].clk_name, rc);
  410. } else {
  411. DEV_ERR("%pS->%s: '%s' is not available\n",
  412. __builtin_return_address(0), __func__,
  413. clk_arry[i].clk_name);
  414. rc = -EPERM;
  415. }
  416. if (rc) {
  417. msm_dss_enable_clk(&clk_arry[i],
  418. i, false);
  419. break;
  420. }
  421. }
  422. } else {
  423. for (i = num_clk - 1; i >= 0; i--) {
  424. DEV_DBG("%pS->%s: disable '%s'\n",
  425. __builtin_return_address(0), __func__,
  426. clk_arry[i].clk_name);
  427. if (clk_arry[i].clk)
  428. clk_disable_unprepare(clk_arry[i].clk);
  429. else
  430. DEV_ERR("%pS->%s: '%s' is not available\n",
  431. __builtin_return_address(0), __func__,
  432. clk_arry[i].clk_name);
  433. }
  434. }
  435. return rc;
  436. } /* msm_dss_enable_clk */
  437. int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
  438. uint8_t reg_offset, uint8_t *read_buf)
  439. {
  440. struct i2c_msg msgs[2];
  441. int ret = -1;
  442. pr_debug("%s: reading from slave_addr=[%x] and offset=[%x]\n",
  443. __func__, slave_addr, reg_offset);
  444. msgs[0].addr = slave_addr >> 1;
  445. msgs[0].flags = 0;
  446. msgs[0].buf = &reg_offset;
  447. msgs[0].len = 1;
  448. msgs[1].addr = slave_addr >> 1;
  449. msgs[1].flags = I2C_M_RD;
  450. msgs[1].buf = read_buf;
  451. msgs[1].len = 1;
  452. ret = i2c_transfer(client->adapter, msgs, 2);
  453. if (ret < 1) {
  454. pr_err("%s: I2C READ FAILED=[%d]\n", __func__, ret);
  455. return -EACCES;
  456. }
  457. pr_debug("%s: i2c buf is [%x]\n", __func__, *read_buf);
  458. return 0;
  459. }
  460. int mdss_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr,
  461. uint8_t reg_offset, uint8_t *value)
  462. {
  463. struct i2c_msg msgs[1];
  464. uint8_t data[2];
  465. int status = -EACCES;
  466. pr_debug("%s: writing from slave_addr=[%x] and offset=[%x]\n",
  467. __func__, slave_addr, reg_offset);
  468. data[0] = reg_offset;
  469. data[1] = *value;
  470. msgs[0].addr = slave_addr >> 1;
  471. msgs[0].flags = 0;
  472. msgs[0].len = 2;
  473. msgs[0].buf = data;
  474. status = i2c_transfer(client->adapter, msgs, 1);
  475. if (status < 1) {
  476. pr_err("I2C WRITE FAILED=[%d]\n", status);
  477. return -EACCES;
  478. }
  479. pr_debug("%s: I2C write status=%x\n", __func__, status);
  480. return status;
  481. }