sde_io_util.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012-2015, 2017-2020 The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/err.h>
  7. #include <linux/io.h>
  8. #include <linux/regulator/consumer.h>
  9. #include <linux/soc/qcom/spmi-pmic-arb.h>
  10. #include <linux/delay.h>
  11. #include <linux/sde_io_util.h>
  12. #include <linux/sde_vm_event.h>
  13. #define MAX_I2C_CMDS 16
  14. void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
  15. {
  16. u32 in_val;
  17. if (!io || !io->base) {
  18. DEV_ERR("%pS->%s: invalid input\n",
  19. __builtin_return_address(0), __func__);
  20. return;
  21. }
  22. if (offset > io->len) {
  23. DEV_ERR("%pS->%s: offset out of range\n",
  24. __builtin_return_address(0), __func__);
  25. return;
  26. }
  27. writel_relaxed(value, io->base + offset);
  28. if (debug) {
  29. in_val = readl_relaxed(io->base + offset);
  30. DEV_DBG("[%08x] => %08x [%08x]\n",
  31. (u32)(unsigned long)(io->base + offset),
  32. value, in_val);
  33. }
  34. } /* dss_reg_w */
  35. EXPORT_SYMBOL(dss_reg_w);
  36. u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug)
  37. {
  38. u32 value;
  39. if (!io || !io->base) {
  40. DEV_ERR("%pS->%s: invalid input\n",
  41. __builtin_return_address(0), __func__);
  42. return -EINVAL;
  43. }
  44. if (offset > io->len) {
  45. DEV_ERR("%pS->%s: offset out of range\n",
  46. __builtin_return_address(0), __func__);
  47. return -EINVAL;
  48. }
  49. value = readl_relaxed(io->base + offset);
  50. if (debug)
  51. DEV_DBG("[%08x] <= %08x\n",
  52. (u32)(unsigned long)(io->base + offset), value);
  53. return value;
  54. } /* dss_reg_r */
  55. EXPORT_SYMBOL(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. EXPORT_SYMBOL(dss_reg_dump);
  64. static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
  65. unsigned int type, const char *name)
  66. {
  67. struct resource *res = NULL;
  68. res = platform_get_resource_byname(pdev, type, name);
  69. if (!res)
  70. DEV_ERR("%s: '%s' resource not found\n", __func__, name);
  71. return res;
  72. } /* msm_dss_get_res_byname */
  73. int msm_dss_ioremap_byname(struct platform_device *pdev,
  74. struct dss_io_data *io_data, const char *name)
  75. {
  76. struct resource *res = NULL;
  77. if (!pdev || !io_data) {
  78. DEV_ERR("%pS->%s: invalid input\n",
  79. __builtin_return_address(0), __func__);
  80. return -EINVAL;
  81. }
  82. res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
  83. if (!res) {
  84. DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n",
  85. __builtin_return_address(0), __func__, name);
  86. return -ENODEV;
  87. }
  88. io_data->len = (u32)resource_size(res);
  89. io_data->base = ioremap(res->start, io_data->len);
  90. if (!io_data->base) {
  91. DEV_ERR("%pS->%s: '%s' ioremap failed\n",
  92. __builtin_return_address(0), __func__, name);
  93. return -EIO;
  94. }
  95. return 0;
  96. } /* msm_dss_ioremap_byname */
  97. EXPORT_SYMBOL(msm_dss_ioremap_byname);
  98. void msm_dss_iounmap(struct dss_io_data *io_data)
  99. {
  100. if (!io_data) {
  101. DEV_ERR("%pS->%s: invalid input\n",
  102. __builtin_return_address(0), __func__);
  103. return;
  104. }
  105. if (io_data->base) {
  106. iounmap(io_data->base);
  107. io_data->base = NULL;
  108. }
  109. io_data->len = 0;
  110. } /* msm_dss_iounmap */
  111. EXPORT_SYMBOL(msm_dss_iounmap);
  112. int msm_dss_get_pmic_io_mem(struct platform_device *pdev,
  113. struct list_head *mem_list)
  114. {
  115. struct list_head temp_head;
  116. struct msm_io_mem_entry *io_mem;
  117. struct resource *res = NULL;
  118. struct property *prop;
  119. const __be32 *cur;
  120. int rc = 0;
  121. u32 val;
  122. INIT_LIST_HEAD(&temp_head);
  123. res = kzalloc(sizeof(struct resource), GFP_KERNEL);
  124. if (!res)
  125. return -ENOMEM;
  126. of_property_for_each_u32(pdev->dev.of_node, "qcom,pmic-arb-address",
  127. prop, cur, val) {
  128. rc = spmi_pmic_arb_map_address(&pdev->dev, val, res);
  129. if (rc < 0) {
  130. DEV_ERR("%pS - failed to map pmic address, rc:%d\n",
  131. __func__, rc);
  132. goto parse_fail;
  133. }
  134. io_mem = kzalloc(sizeof(struct msm_io_mem_entry), GFP_KERNEL);
  135. if (!io_mem) {
  136. rc = -ENOMEM;
  137. goto parse_fail;
  138. }
  139. io_mem->base = res->start;
  140. io_mem->size = resource_size(res);
  141. list_add(&io_mem->list, &temp_head);
  142. }
  143. list_splice(&temp_head, mem_list);
  144. goto end;
  145. parse_fail:
  146. msm_dss_clean_io_mem(&temp_head);
  147. end:
  148. kzfree(res);
  149. return rc;
  150. }
  151. EXPORT_SYMBOL(msm_dss_get_pmic_io_mem);
  152. int msm_dss_get_io_mem(struct platform_device *pdev, struct list_head *mem_list)
  153. {
  154. struct list_head temp_head;
  155. struct msm_io_mem_entry *io_mem;
  156. struct resource *res = NULL;
  157. const char *reg_name, *exclude_reg_name;
  158. int i, j, rc = 0;
  159. int num_entry, num_exclude_entry;
  160. INIT_LIST_HEAD(&temp_head);
  161. num_entry = of_property_count_strings(pdev->dev.of_node,
  162. "reg-names");
  163. if (num_entry < 0)
  164. num_entry = 0;
  165. /*
  166. * check the dt property to know whether the platform device wants
  167. * to exclude any reg ranges from the IO list
  168. */
  169. num_exclude_entry = of_property_count_strings(pdev->dev.of_node,
  170. "qcom,sde-vm-exclude-reg-names");
  171. if (num_exclude_entry < 0)
  172. num_exclude_entry = 0;
  173. for (i = 0; i < num_entry; i++) {
  174. bool exclude = false;
  175. of_property_read_string_index(pdev->dev.of_node,
  176. "reg-names", i, &reg_name);
  177. for (j = 0; j < num_exclude_entry; j++) {
  178. of_property_read_string_index(pdev->dev.of_node,
  179. "qcom,sde-vm-exclude-reg-names", j,
  180. &exclude_reg_name);
  181. if (!strcmp(reg_name, exclude_reg_name)) {
  182. exclude = true;
  183. break;
  184. }
  185. }
  186. if (exclude)
  187. continue;
  188. res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
  189. reg_name);
  190. if (!res)
  191. break;
  192. io_mem = kzalloc(sizeof(*io_mem), GFP_KERNEL);
  193. if (!io_mem) {
  194. msm_dss_clean_io_mem(&temp_head);
  195. rc = -ENOMEM;
  196. goto parse_fail;
  197. }
  198. io_mem->base = res->start;
  199. io_mem->size = resource_size(res);
  200. list_add(&io_mem->list, &temp_head);
  201. }
  202. list_splice(&temp_head, mem_list);
  203. return 0;
  204. parse_fail:
  205. msm_dss_clean_io_mem(&temp_head);
  206. return rc;
  207. }
  208. EXPORT_SYMBOL(msm_dss_get_io_mem);
  209. void msm_dss_clean_io_mem(struct list_head *mem_list)
  210. {
  211. struct msm_io_mem_entry *pos, *tmp;
  212. list_for_each_entry_safe(pos, tmp, mem_list, list) {
  213. list_del(&pos->list);
  214. kzfree(pos);
  215. }
  216. }
  217. EXPORT_SYMBOL(msm_dss_clean_io_mem);
  218. int msm_dss_get_io_irq(struct platform_device *pdev, struct list_head *irq_list,
  219. u32 label)
  220. {
  221. struct msm_io_irq_entry *io_irq;
  222. int irq;
  223. irq = platform_get_irq(pdev, 0);
  224. if (irq < 0) {
  225. pr_err("invalid IRQ\n");
  226. return irq;
  227. }
  228. io_irq = kzalloc(sizeof(*io_irq), GFP_KERNEL);
  229. if (!io_irq)
  230. return -ENOMEM;
  231. io_irq->label = label;
  232. io_irq->irq_num = irq;
  233. list_add(&io_irq->list, irq_list);
  234. return 0;
  235. }
  236. EXPORT_SYMBOL(msm_dss_get_io_irq);
  237. void msm_dss_clean_io_irq(struct list_head *irq_list)
  238. {
  239. struct msm_io_irq_entry *pos, *tmp;
  240. list_for_each_entry_safe(pos, tmp, irq_list, list) {
  241. list_del(&pos->list);
  242. kzfree(pos);
  243. }
  244. }
  245. EXPORT_SYMBOL(msm_dss_clean_io_irq);
  246. int msm_dss_get_vreg(struct device *dev, struct dss_vreg *in_vreg,
  247. int num_vreg, int enable)
  248. {
  249. int i = 0, rc = 0;
  250. struct dss_vreg *curr_vreg = NULL;
  251. if (!in_vreg || !num_vreg)
  252. return rc;
  253. if (enable) {
  254. for (i = 0; i < num_vreg; i++) {
  255. curr_vreg = &in_vreg[i];
  256. curr_vreg->vreg = regulator_get(dev,
  257. curr_vreg->vreg_name);
  258. rc = PTR_ERR_OR_ZERO(curr_vreg->vreg);
  259. if (rc) {
  260. DEV_ERR("%pS->%s: %s get failed. rc=%d\n",
  261. __builtin_return_address(0), __func__,
  262. curr_vreg->vreg_name, rc);
  263. curr_vreg->vreg = NULL;
  264. goto vreg_get_fail;
  265. }
  266. }
  267. } else {
  268. for (i = num_vreg-1; i >= 0; i--) {
  269. curr_vreg = &in_vreg[i];
  270. if (curr_vreg->vreg) {
  271. regulator_put(curr_vreg->vreg);
  272. curr_vreg->vreg = NULL;
  273. }
  274. }
  275. }
  276. return 0;
  277. vreg_get_fail:
  278. for (i--; i >= 0; i--) {
  279. curr_vreg = &in_vreg[i];
  280. regulator_set_load(curr_vreg->vreg, 0);
  281. regulator_put(curr_vreg->vreg);
  282. curr_vreg->vreg = NULL;
  283. }
  284. return rc;
  285. } /* msm_dss_get_vreg */
  286. EXPORT_SYMBOL(msm_dss_get_vreg);
  287. static bool msm_dss_is_hw_controlled(struct dss_vreg in_vreg)
  288. {
  289. u32 mode = 0;
  290. char const *regulator_gdsc = "gdsc";
  291. /*
  292. * For gdsc-regulator devices only, REGULATOR_MODE_FAST specifies that
  293. * the GDSC is in HW controlled mode.
  294. */
  295. mode = regulator_get_mode(in_vreg.vreg);
  296. if (!strcmp(regulator_gdsc, in_vreg.vreg_name) &&
  297. mode == REGULATOR_MODE_FAST) {
  298. DEV_DBG("%pS->%s: %s is HW controlled\n",
  299. __builtin_return_address(0), __func__,
  300. in_vreg.vreg_name);
  301. return true;
  302. }
  303. return false;
  304. }
  305. int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
  306. {
  307. int i = 0, rc = 0;
  308. bool need_sleep;
  309. if (enable) {
  310. for (i = 0; i < num_vreg; i++) {
  311. rc = PTR_ERR_OR_ZERO(in_vreg[i].vreg);
  312. if (rc) {
  313. DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
  314. __builtin_return_address(0), __func__,
  315. in_vreg[i].vreg_name, rc);
  316. goto vreg_set_opt_mode_fail;
  317. }
  318. if (msm_dss_is_hw_controlled(in_vreg[i]))
  319. continue;
  320. need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
  321. if (in_vreg[i].pre_on_sleep && need_sleep)
  322. usleep_range(in_vreg[i].pre_on_sleep * 1000,
  323. (in_vreg[i].pre_on_sleep * 1000) + 10);
  324. rc = regulator_set_load(in_vreg[i].vreg,
  325. in_vreg[i].enable_load);
  326. if (rc < 0) {
  327. DEV_ERR("%pS->%s: %s set opt m fail\n",
  328. __builtin_return_address(0), __func__,
  329. in_vreg[i].vreg_name);
  330. goto vreg_set_opt_mode_fail;
  331. }
  332. if (regulator_count_voltages(in_vreg[i].vreg) > 0)
  333. regulator_set_voltage(in_vreg[i].vreg,
  334. in_vreg[i].min_voltage,
  335. in_vreg[i].max_voltage);
  336. rc = regulator_enable(in_vreg[i].vreg);
  337. if (in_vreg[i].post_on_sleep && need_sleep)
  338. usleep_range(in_vreg[i].post_on_sleep * 1000,
  339. (in_vreg[i].post_on_sleep * 1000) + 10);
  340. if (rc < 0) {
  341. DEV_ERR("%pS->%s: %s enable failed\n",
  342. __builtin_return_address(0), __func__,
  343. in_vreg[i].vreg_name);
  344. goto disable_vreg;
  345. }
  346. }
  347. } else {
  348. for (i = num_vreg-1; i >= 0; i--) {
  349. if (msm_dss_is_hw_controlled(in_vreg[i]))
  350. continue;
  351. if (in_vreg[i].pre_off_sleep)
  352. usleep_range(in_vreg[i].pre_off_sleep * 1000,
  353. (in_vreg[i].pre_off_sleep * 1000) + 10);
  354. regulator_disable(in_vreg[i].vreg);
  355. if (in_vreg[i].post_off_sleep)
  356. usleep_range(in_vreg[i].post_off_sleep * 1000,
  357. (in_vreg[i].post_off_sleep * 1000) + 10);
  358. regulator_set_load(in_vreg[i].vreg,
  359. in_vreg[i].disable_load);
  360. if (regulator_count_voltages(in_vreg[i].vreg) > 0)
  361. regulator_set_voltage(in_vreg[i].vreg, 0,
  362. in_vreg[i].max_voltage);
  363. }
  364. }
  365. return rc;
  366. disable_vreg:
  367. regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load);
  368. vreg_set_opt_mode_fail:
  369. for (i--; i >= 0; i--) {
  370. if (in_vreg[i].pre_off_sleep)
  371. usleep_range(in_vreg[i].pre_off_sleep * 1000,
  372. (in_vreg[i].pre_off_sleep * 1000) + 10);
  373. regulator_disable(in_vreg[i].vreg);
  374. if (in_vreg[i].post_off_sleep)
  375. usleep_range(in_vreg[i].post_off_sleep * 1000,
  376. (in_vreg[i].post_off_sleep * 1000) + 10);
  377. regulator_set_load(in_vreg[i].vreg,
  378. in_vreg[i].disable_load);
  379. }
  380. return rc;
  381. } /* msm_dss_enable_vreg */
  382. EXPORT_SYMBOL(msm_dss_enable_vreg);
  383. int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable)
  384. {
  385. int i = 0, rc = 0;
  386. if (enable) {
  387. for (i = 0; i < num_gpio; i++) {
  388. DEV_DBG("%pS->%s: %s enable\n",
  389. __builtin_return_address(0), __func__,
  390. in_gpio[i].gpio_name);
  391. rc = gpio_request(in_gpio[i].gpio,
  392. in_gpio[i].gpio_name);
  393. if (rc < 0) {
  394. DEV_ERR("%pS->%s: %s enable failed\n",
  395. __builtin_return_address(0), __func__,
  396. in_gpio[i].gpio_name);
  397. goto disable_gpio;
  398. }
  399. gpio_set_value(in_gpio[i].gpio, in_gpio[i].value);
  400. }
  401. } else {
  402. for (i = num_gpio-1; i >= 0; i--) {
  403. DEV_DBG("%pS->%s: %s disable\n",
  404. __builtin_return_address(0), __func__,
  405. in_gpio[i].gpio_name);
  406. if (in_gpio[i].gpio)
  407. gpio_free(in_gpio[i].gpio);
  408. }
  409. }
  410. return rc;
  411. disable_gpio:
  412. for (i--; i >= 0; i--)
  413. if (in_gpio[i].gpio)
  414. gpio_free(in_gpio[i].gpio);
  415. return rc;
  416. } /* msm_dss_enable_gpio */
  417. EXPORT_SYMBOL(msm_dss_enable_gpio);
  418. void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
  419. {
  420. int i;
  421. for (i = num_clk - 1; i >= 0; i--) {
  422. if (clk_arry[i].clk)
  423. clk_put(clk_arry[i].clk);
  424. clk_arry[i].clk = NULL;
  425. }
  426. } /* msm_dss_put_clk */
  427. EXPORT_SYMBOL(msm_dss_put_clk);
  428. int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
  429. {
  430. int i, rc = 0;
  431. for (i = 0; i < num_clk; i++) {
  432. clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
  433. rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
  434. if (rc) {
  435. DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
  436. __builtin_return_address(0), __func__,
  437. clk_arry[i].clk_name, rc);
  438. goto error;
  439. }
  440. }
  441. return rc;
  442. error:
  443. for (i--; i >= 0; i--) {
  444. if (clk_arry[i].clk)
  445. clk_put(clk_arry[i].clk);
  446. clk_arry[i].clk = NULL;
  447. }
  448. return rc;
  449. } /* msm_dss_get_clk */
  450. EXPORT_SYMBOL(msm_dss_get_clk);
  451. int msm_dss_single_clk_set_rate(struct dss_clk *clk)
  452. {
  453. int rc = 0;
  454. if (!clk) {
  455. DEV_ERR("invalid clk struct\n");
  456. return -EINVAL;
  457. }
  458. DEV_DBG("%pS->%s: set_rate '%s'\n",
  459. __builtin_return_address(0), __func__,
  460. clk->clk_name);
  461. if (clk->type != DSS_CLK_AHB) {
  462. rc = clk_set_rate(clk->clk, clk->rate);
  463. if (rc)
  464. DEV_ERR("%pS->%s: %s failed. rc=%d\n",
  465. __builtin_return_address(0),
  466. __func__,
  467. clk->clk_name, rc);
  468. }
  469. return rc;
  470. } /* msm_dss_single_clk_set_rate */
  471. EXPORT_SYMBOL(msm_dss_single_clk_set_rate);
  472. int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
  473. {
  474. int i, rc = 0;
  475. for (i = 0; i < num_clk; i++) {
  476. if (clk_arry[i].clk) {
  477. rc = msm_dss_single_clk_set_rate(&clk_arry[i]);
  478. if (rc)
  479. break;
  480. } else {
  481. DEV_ERR("%pS->%s: '%s' is not available\n",
  482. __builtin_return_address(0), __func__,
  483. clk_arry[i].clk_name);
  484. rc = -EPERM;
  485. break;
  486. }
  487. }
  488. return rc;
  489. } /* msm_dss_clk_set_rate */
  490. EXPORT_SYMBOL(msm_dss_clk_set_rate);
  491. int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
  492. {
  493. int i, rc = 0;
  494. if (enable) {
  495. for (i = 0; i < num_clk; i++) {
  496. DEV_DBG("%pS->%s: enable '%s'\n",
  497. __builtin_return_address(0), __func__,
  498. clk_arry[i].clk_name);
  499. if (clk_arry[i].clk) {
  500. rc = clk_prepare_enable(clk_arry[i].clk);
  501. if (rc)
  502. DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
  503. __builtin_return_address(0),
  504. __func__,
  505. clk_arry[i].clk_name, rc);
  506. } else {
  507. DEV_ERR("%pS->%s: '%s' is not available\n",
  508. __builtin_return_address(0), __func__,
  509. clk_arry[i].clk_name);
  510. rc = -EPERM;
  511. }
  512. if (rc) {
  513. msm_dss_enable_clk(clk_arry, i, false);
  514. break;
  515. }
  516. }
  517. } else {
  518. for (i = num_clk - 1; i >= 0; i--) {
  519. DEV_DBG("%pS->%s: disable '%s'\n",
  520. __builtin_return_address(0), __func__,
  521. clk_arry[i].clk_name);
  522. if (clk_arry[i].clk)
  523. clk_disable_unprepare(clk_arry[i].clk);
  524. else
  525. DEV_ERR("%pS->%s: '%s' is not available\n",
  526. __builtin_return_address(0), __func__,
  527. clk_arry[i].clk_name);
  528. }
  529. }
  530. return rc;
  531. } /* msm_dss_enable_clk */
  532. EXPORT_SYMBOL(msm_dss_enable_clk);
  533. int sde_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
  534. uint8_t reg_offset, uint8_t *read_buf)
  535. {
  536. struct i2c_msg msgs[2];
  537. int ret = -1;
  538. pr_debug("%s: reading from slave_addr=[%x] and offset=[%x]\n",
  539. __func__, slave_addr, reg_offset);
  540. msgs[0].addr = slave_addr >> 1;
  541. msgs[0].flags = 0;
  542. msgs[0].buf = &reg_offset;
  543. msgs[0].len = 1;
  544. msgs[1].addr = slave_addr >> 1;
  545. msgs[1].flags = I2C_M_RD;
  546. msgs[1].buf = read_buf;
  547. msgs[1].len = 1;
  548. ret = i2c_transfer(client->adapter, msgs, 2);
  549. if (ret < 1) {
  550. pr_err("%s: I2C READ FAILED=[%d]\n", __func__, ret);
  551. return -EACCES;
  552. }
  553. pr_debug("%s: i2c buf is [%x]\n", __func__, *read_buf);
  554. return 0;
  555. }
  556. EXPORT_SYMBOL(sde_i2c_byte_read);
  557. int sde_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr,
  558. uint8_t reg_offset, uint8_t *value)
  559. {
  560. struct i2c_msg msgs[1];
  561. uint8_t data[2];
  562. int status = -EACCES;
  563. pr_debug("%s: writing from slave_addr=[%x] and offset=[%x]\n",
  564. __func__, slave_addr, reg_offset);
  565. data[0] = reg_offset;
  566. data[1] = *value;
  567. msgs[0].addr = slave_addr >> 1;
  568. msgs[0].flags = 0;
  569. msgs[0].len = 2;
  570. msgs[0].buf = data;
  571. status = i2c_transfer(client->adapter, msgs, 1);
  572. if (status < 1) {
  573. pr_err("I2C WRITE FAILED=[%d]\n", status);
  574. return -EACCES;
  575. }
  576. pr_debug("%s: I2C write status=%x\n", __func__, status);
  577. return status;
  578. }
  579. EXPORT_SYMBOL(sde_i2c_byte_write);