ast_ddc.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // SPDX-License-Identifier: MIT
  2. /*
  3. * Permission is hereby granted, free of charge, to any person obtaining a
  4. * copy of this software and associated documentation files (the
  5. * "Software"), to deal in the Software without restriction, including
  6. * without limitation the rights to use, copy, modify, merge, publish,
  7. * distribute, sub license, and/or sell copies of the Software, and to
  8. * permit persons to whom the Software is furnished to do so, subject to
  9. * the following conditions:
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  14. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  15. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  17. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. *
  19. * The above copyright notice and this permission notice (including the
  20. * next paragraph) shall be included in all copies or substantial portions
  21. * of the Software.
  22. */
  23. #include <linux/i2c-algo-bit.h>
  24. #include <linux/i2c.h>
  25. #include <drm/drm_managed.h>
  26. #include <drm/drm_print.h>
  27. #include "ast_ddc.h"
  28. #include "ast_drv.h"
  29. struct ast_ddc {
  30. struct ast_device *ast;
  31. struct i2c_algo_bit_data bit;
  32. struct i2c_adapter adapter;
  33. };
  34. static void ast_ddc_algo_bit_data_setsda(void *data, int state)
  35. {
  36. struct ast_ddc *ddc = data;
  37. struct ast_device *ast = ddc->ast;
  38. int i;
  39. u8 ujcrb7, jtemp;
  40. for (i = 0; i < 0x10000; i++) {
  41. ujcrb7 = ((state & 0x01) ? 0 : 1) << 2;
  42. ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0xf1, ujcrb7);
  43. jtemp = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x04);
  44. if (ujcrb7 == jtemp)
  45. break;
  46. }
  47. }
  48. static void ast_ddc_algo_bit_data_setscl(void *data, int state)
  49. {
  50. struct ast_ddc *ddc = data;
  51. struct ast_device *ast = ddc->ast;
  52. int i;
  53. u8 ujcrb7, jtemp;
  54. for (i = 0; i < 0x10000; i++) {
  55. ujcrb7 = ((state & 0x01) ? 0 : 1);
  56. ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0xf4, ujcrb7);
  57. jtemp = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x01);
  58. if (ujcrb7 == jtemp)
  59. break;
  60. }
  61. }
  62. static int ast_ddc_algo_bit_data_pre_xfer(struct i2c_adapter *adapter)
  63. {
  64. struct ast_ddc *ddc = i2c_get_adapdata(adapter);
  65. struct ast_device *ast = ddc->ast;
  66. /*
  67. * Protect access to I/O registers from concurrent modesetting
  68. * by acquiring the I/O-register lock.
  69. */
  70. mutex_lock(&ast->modeset_lock);
  71. return 0;
  72. }
  73. static void ast_ddc_algo_bit_data_post_xfer(struct i2c_adapter *adapter)
  74. {
  75. struct ast_ddc *ddc = i2c_get_adapdata(adapter);
  76. struct ast_device *ast = ddc->ast;
  77. mutex_unlock(&ast->modeset_lock);
  78. }
  79. static int ast_ddc_algo_bit_data_getsda(void *data)
  80. {
  81. struct ast_ddc *ddc = data;
  82. struct ast_device *ast = ddc->ast;
  83. uint32_t val, val2, count, pass;
  84. count = 0;
  85. pass = 0;
  86. val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x20) >> 5) & 0x01;
  87. do {
  88. val2 = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x20) >> 5) & 0x01;
  89. if (val == val2) {
  90. pass++;
  91. } else {
  92. pass = 0;
  93. val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x20) >> 5) & 0x01;
  94. }
  95. } while ((pass < 5) && (count++ < 0x10000));
  96. return val & 1 ? 1 : 0;
  97. }
  98. static int ast_ddc_algo_bit_data_getscl(void *data)
  99. {
  100. struct ast_ddc *ddc = data;
  101. struct ast_device *ast = ddc->ast;
  102. uint32_t val, val2, count, pass;
  103. count = 0;
  104. pass = 0;
  105. val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x10) >> 4) & 0x01;
  106. do {
  107. val2 = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x10) >> 4) & 0x01;
  108. if (val == val2) {
  109. pass++;
  110. } else {
  111. pass = 0;
  112. val = (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x10) >> 4) & 0x01;
  113. }
  114. } while ((pass < 5) && (count++ < 0x10000));
  115. return val & 1 ? 1 : 0;
  116. }
  117. static void ast_ddc_release(struct drm_device *dev, void *res)
  118. {
  119. struct ast_ddc *ddc = res;
  120. i2c_del_adapter(&ddc->adapter);
  121. }
  122. struct i2c_adapter *ast_ddc_create(struct ast_device *ast)
  123. {
  124. struct drm_device *dev = &ast->base;
  125. struct ast_ddc *ddc;
  126. struct i2c_adapter *adapter;
  127. struct i2c_algo_bit_data *bit;
  128. int ret;
  129. ddc = drmm_kzalloc(dev, sizeof(*ddc), GFP_KERNEL);
  130. if (!ddc)
  131. return ERR_PTR(-ENOMEM);
  132. ddc->ast = ast;
  133. bit = &ddc->bit;
  134. bit->data = ddc;
  135. bit->setsda = ast_ddc_algo_bit_data_setsda;
  136. bit->setscl = ast_ddc_algo_bit_data_setscl;
  137. bit->getsda = ast_ddc_algo_bit_data_getsda;
  138. bit->getscl = ast_ddc_algo_bit_data_getscl;
  139. bit->pre_xfer = ast_ddc_algo_bit_data_pre_xfer;
  140. bit->post_xfer = ast_ddc_algo_bit_data_post_xfer;
  141. bit->udelay = 20;
  142. bit->timeout = usecs_to_jiffies(2200);
  143. adapter = &ddc->adapter;
  144. adapter->owner = THIS_MODULE;
  145. adapter->algo_data = bit;
  146. adapter->dev.parent = dev->dev;
  147. snprintf(adapter->name, sizeof(adapter->name), "AST DDC bus");
  148. i2c_set_adapdata(adapter, ddc);
  149. ret = i2c_bit_add_bus(adapter);
  150. if (ret) {
  151. drm_err(dev, "Failed to register bit i2c\n");
  152. return ERR_PTR(ret);
  153. }
  154. ret = drmm_add_action_or_reset(dev, ast_ddc_release, ddc);
  155. if (ret)
  156. return ERR_PTR(ret);
  157. return &ddc->adapter;
  158. }