<div style="line-height:1.7;color:#000000;font-size:14px;font-family:Arial"><p style="margin:0;">Hi, sunhao.</p><p style="margin:0;"><br></p><p style="margin:0;">> </p><p style="margin:0;">> Add GPIO and I2C driver to detect connector and fetch EDID via DDC.</p><div style="margin:0;">> </div><div style="margin:0;">It's even better to add what V2 has changed.</div><div style="margin:0;">> Signed-off-by: Hao Sun <sunhao@loongson.cn></div><p style="margin:0;">> ---</p><p style="margin:0;">>  drivers/gpu/drm/loongson/Makefile             |   3 +-</p><p style="margin:0;">>  drivers/gpu/drm/loongson/loongson_connector.c | 120 +++++++-</p><p style="margin:0;">>  drivers/gpu/drm/loongson/loongson_drv.c       |  16 +-</p><p style="margin:0;">>  drivers/gpu/drm/loongson/loongson_drv.h       |  10 +</p><p style="margin:0;">>  drivers/gpu/drm/loongson/loongson_i2c.c       | 264 ++++++++++++++++++</p><p style="margin:0;">>  drivers/gpu/drm/loongson/loongson_i2c.h       |  40 +++</p><p style="margin:0;">>  6 files changed, 446 insertions(+), 7 deletions(-)</p><p style="margin:0;">>  create mode 100644 drivers/gpu/drm/loongson/loongson_i2c.c</p><p style="margin:0;">>  create mode 100644 drivers/gpu/drm/loongson/loongson_i2c.h</p><p style="margin:0;">> </p><p style="margin:0;">> diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile</p><p style="margin:0;">> index 22d063953..773b806e9 100644</p><p style="margin:0;">> --- a/drivers/gpu/drm/loongson/Makefile</p><p style="margin:0;">> +++ b/drivers/gpu/drm/loongson/Makefile</p><p style="margin:0;">> @@ -10,5 +10,6 @@ loongson-y := loongson_drv.o \</p><p style="margin:0;">>  <span style="white-space:pre">   </span>loongson_plane.o \</p><p style="margin:0;">>  <span style="white-space:pre"> </span>loongson_device.o \</p><p style="margin:0;">>  <span style="white-space:pre">        </span>loongson_connector.o \</p><p style="margin:0;">> -<span style="white-space:pre">  </span>loongson_encoder.o</p><p style="margin:0;">> +<span style="white-space:pre">      </span>loongson_encoder.o \</p><p style="margin:0;">> +<span style="white-space:pre">    </span>loongson_i2c.o</p><p style="margin:0;">>  obj-$(CONFIG_DRM_LOONGSON) += loongson.o</p><p style="margin:0;">> diff --git a/drivers/gpu/drm/loongson/loongson_connector.c b/drivers/gpu/drm/loongson/loongson_connector.c</p><p style="margin:0;">> index 6b1f0ffa3..e0aea8553 100644</p><p style="margin:0;">> --- a/drivers/gpu/drm/loongson/loongson_connector.c</p><p style="margin:0;">> +++ b/drivers/gpu/drm/loongson/loongson_connector.c</p><p style="margin:0;">> @@ -2,14 +2,117 @@</p><p style="margin:0;">>  </p><p style="margin:0;">>  #include "loongson_drv.h"</p><p style="margin:0;">>  </p><p style="margin:0;">> +static int loongson_do_probe_ddc_edid(struct i2c_adapter *adapter,</p><p style="margin:0;">> +<span style="white-space:pre">                               </span>      unsigned char *buf)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">  </span>u8 start = 0x0;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>u32 che_tmp = 0;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>u32 i;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">     </span>struct i2c_msg msgs[] = { {</p><p style="margin:0;">> +<span style="white-space:pre">             </span>.addr = DDC_ADDR,</p><p style="margin:0;">> +<span style="white-space:pre">               </span>.flags = 0,</p><p style="margin:0;">> +<span style="white-space:pre">             </span>.len = 1,</p><p style="margin:0;">> +<span style="white-space:pre">               </span>.buf = &start,</p><p style="margin:0;">> +<span style="white-space:pre">      </span>},</p><p style="margin:0;">> +<span style="white-space:pre">      </span>{</p><p style="margin:0;">> +<span style="white-space:pre">               </span>.addr = DDC_ADDR,</p><p style="margin:0;">> +<span style="white-space:pre">               </span>.flags = I2C_M_RD,</p><p style="margin:0;">> +<span style="white-space:pre">              </span>.len = EDID_LENGTH * 2,</p><p style="margin:0;">> +<span style="white-space:pre">         </span>.buf = buf,</p><p style="margin:0;">> +<span style="white-space:pre">     </span>} };</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">       </span>if (i2c_transfer(adapter, msgs, 2) == 2) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>if (buf[126] != 0) {</p><p style="margin:0;">> +<span style="white-space:pre">                    </span>buf[126] = 0;</p><p style="margin:0;">> +<span style="white-space:pre">                   </span>che_tmp = 0;</p><p style="margin:0;">> +<span style="white-space:pre">                    </span>for (i = 0; i < 127; i++)</p><p style="margin:0;">> +<span style="white-space:pre">                            </span>che_tmp += buf[i];</p><p style="margin:0;">> +<span style="white-space:pre">                      </span>buf[127] = 256 - (che_tmp) % 256;</p><p style="margin:0;">> +<span style="white-space:pre">               </span>}</p><p style="margin:0;">> +<span style="white-space:pre">               </span>if (!drm_edid_block_valid(buf, 0, true, NULL)) {</p><p style="margin:0;">> +<span style="white-space:pre">                        </span>dev_warn_once(&adapter->dev, "Invalid EDID block\n");</p><p style="margin:0;">> +<span style="white-space:pre">                  </span>return false;</p><p style="margin:0;">> +<span style="white-space:pre">           </span>}</p><p style="margin:0;">> +<span style="white-space:pre">       </span>} else {</p><p style="margin:0;">> +<span style="white-space:pre">                </span>dev_warn_once(&adapter->dev, "unable to read EDID block\n");</p><p style="margin:0;">> +<span style="white-space:pre">           </span>return false;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>return true;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static bool get_edid_i2c(struct loongson_connector *lconnector, u8 *edid)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">     </span>struct loongson_i2c *i2c = lconnector->i2c;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>bool ret = false;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>if (i2c != NULL && i2c->adapter != NULL)</p><p style="margin:0;">> +<span style="white-space:pre">             </span>ret = loongson_do_probe_ddc_edid(i2c->adapter, edid);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>else</p><p style="margin:0;">> +<span style="white-space:pre">            </span>DRM_INFO_ONCE("get loongson connector adapter err\n");</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">   </span>return ret;</p><div style="margin:0;">> +}</div><div style="margin:0;">can use drm_get_edid get edid£¬you can delete get_edid_i2c and loongson_do_probe_ddc_edid</div><p style="margin:0;">> +</p><p style="margin:0;">>  static int loongson_get_modes(struct drm_connector *connector)</p><p style="margin:0;">>  {</p><p style="margin:0;">> -<span style="white-space:pre">       </span>int count;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>struct loongson_connector *lconnector;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>u8 edid[EDID_LENGTH * 2];</p><p style="margin:0;">> +<span style="white-space:pre">       </span>u32 size;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>bool success;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>u32 ret;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">   </span>lconnector = to_loongson_connector(connector);</p><p style="margin:0;">> +<span style="white-space:pre">  </span>size = sizeof(u8) * EDID_LENGTH * 2;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">       </span>success = get_edid_i2c(lconnector, edid);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>if (success) {</p><p style="margin:0;">> +<span style="white-space:pre">          </span>drm_connector_update_edid_property(connector,</p><p style="margin:0;">> +<span style="white-space:pre">                           </span>(struct edid *)edid);</p><p style="margin:0;">> +<span style="white-space:pre">           </span>ret = drm_add_edid_modes(connector, (struct edid *)edid);</p><p style="margin:0;">> +<span style="white-space:pre">       </span>} else</p><p style="margin:0;">> +<span style="white-space:pre">          </span>ret = drm_add_modes_noedid(connector, 1024, 768);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>return ret;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static bool is_connected(struct loongson_connector *ls_connector)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">      </span>unsigned char start = 0x0;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>struct i2c_adapter *adapter;</p><p style="margin:0;">> +<span style="white-space:pre">    </span>struct i2c_msg msgs = {</p><p style="margin:0;">> +<span style="white-space:pre">         </span>.addr = DDC_ADDR,</p><p style="margin:0;">> +<span style="white-space:pre">               </span>.flags = 0,</p><p style="margin:0;">> +<span style="white-space:pre">             </span>.len = 1,</p><p style="margin:0;">> +<span style="white-space:pre">               </span>.buf = &start,</p><p style="margin:0;">> +<span style="white-space:pre">      </span>};</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre"> </span>if (!ls_connector->i2c)</p><p style="margin:0;">> +<span style="white-space:pre">              </span>return false;</p><p style="margin:0;">>  </p><p style="margin:0;">> -<span style="white-space:pre">    </span>count = drm_add_modes_noedid(connector, 1920, 1080);</p><p style="margin:0;">> -<span style="white-space:pre">    </span>drm_set_preferred_mode(connector, 1024, 768);</p><p style="margin:0;">> +<span style="white-space:pre">   </span>adapter = ls_connector->i2c->adapter;</p><p style="margin:0;">> +<span style="white-space:pre">     </span>if (i2c_transfer(adapter, &msgs, 1) != 1) {</p><p style="margin:0;">> +<span style="white-space:pre">         </span>DRM_DEBUG_KMS("display-%d not connect\n", ls_connector->id);</p><p style="margin:0;">> +<span style="white-space:pre">               </span>return false;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>}</p><p style="margin:0;">>  </p><p style="margin:0;">> -<span style="white-space:pre">        </span>return count;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>return true;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static enum drm_connector_status</p><p style="margin:0;">> +loongson_detect(struct drm_connector *connector, bool force)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">     </span>struct loongson_connector *lconnector;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>enum drm_connector_status ret = connector_status_disconnected;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">     </span>lconnector = to_loongson_connector(connector);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">     </span>if (is_connected(lconnector))</p><p style="margin:0;">> +<span style="white-space:pre">           </span>ret = connector_status_connected;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>return ret;</p><p style="margin:0;">>  }</p><p style="margin:0;">>  </p><p style="margin:0;">>  static const struct drm_connector_helper_funcs loongson_connector_helper = {</p><p style="margin:0;">> @@ -17,6 +120,7 @@ static const struct drm_connector_helper_funcs loongson_connector_helper = {</p><p style="margin:0;">>  };</p><p style="margin:0;">>  </p><p style="margin:0;">>  static const struct drm_connector_funcs loongson_connector_funcs = {</p><p style="margin:0;">> +<span style="white-space:pre"> </span>.detect = loongson_detect,</p><p style="margin:0;">>  <span style="white-space:pre"> </span>.fill_modes = drm_helper_probe_single_connector_modes,</p><p style="margin:0;">>  <span style="white-space:pre">     </span>.destroy = drm_connector_cleanup,</p><p style="margin:0;">>  <span style="white-space:pre">  </span>.reset = drm_atomic_helper_connector_reset,</p><p style="margin:0;">> @@ -37,11 +141,17 @@ int loongson_connector_init(struct loongson_device *ldev, int index)</p><p style="margin:0;">>  </p><p style="margin:0;">>  <span style="white-space:pre">    </span>lconnector->ldev = ldev;</p><p style="margin:0;">>  <span style="white-space:pre">        </span>lconnector->id = index;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>lconnector->i2c_id = index + DC_I2C_BASE;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">       </span>lconnector->i2c = loongson_i2c_bus_match(ldev, lconnector->i2c_id);</p><p style="margin:0;">> +<span style="white-space:pre">       </span>if (!lconnector->i2c)</p><p style="margin:0;">> +<span style="white-space:pre">                </span>DRM_INFO("connector-%d match i2c-%d err\n", index,</p><p style="margin:0;">> +<span style="white-space:pre">                    </span> lconnector->i2c_id);</p><p style="margin:0;">>  </p><p style="margin:0;">>  <span style="white-space:pre">    </span>ldev->mode_info[index].connector = lconnector;</p><p style="margin:0;">>  <span style="white-space:pre">  </span>connector = &lconnector->base;</p><p style="margin:0;">>  <span style="white-space:pre">      </span>drm_connector_init(ldev->dev, connector, &loongson_connector_funcs,</p><p style="margin:0;">> -<span style="white-space:pre">                      </span>   DRM_MODE_CONNECTOR_Unknown);</p><p style="margin:0;">> +<span style="white-space:pre">                       </span>DRM_MODE_CONNECTOR_Unknown);</p><p style="margin:0;">>  <span style="white-space:pre">       </span>drm_connector_helper_add(connector, &loongson_connector_helper);</p><p style="margin:0;">>  </p><p style="margin:0;">>  <span style="white-space:pre">        </span>return 0;</p><p style="margin:0;">> diff --git a/drivers/gpu/drm/loongson/loongson_drv.c b/drivers/gpu/drm/loongson/loongson_drv.c</p><p style="margin:0;">> index e405199a3..252be9e25 100644</p><p style="margin:0;">> --- a/drivers/gpu/drm/loongson/loongson_drv.c</p><p style="margin:0;">> +++ b/drivers/gpu/drm/loongson/loongson_drv.c</p><p style="margin:0;">> @@ -11,9 +11,10 @@</p><p style="margin:0;">>  </p><p style="margin:0;">>  /* Interface history:</p><p style="margin:0;">>   * 0.1 - original.</p><p style="margin:0;">> + * 0.2 - add i2c and connector detect.</p><p style="margin:0;">>   */</p><p style="margin:0;">>  #define DRIVER_MAJOR 0</p><p style="margin:0;">> -#define DRIVER_MINOR 1</p><p style="margin:0;">> +#define DRIVER_MINOR 2</p><p style="margin:0;">>  </p><p style="margin:0;">>  static const struct drm_mode_config_funcs loongson_mode_funcs = {</p><p style="margin:0;">>  <span style="white-space:pre">       </span>.fb_create = drm_gem_fb_create,</p><p style="margin:0;">> @@ -31,6 +32,7 @@ static int loongson_device_init(struct drm_device *dev, uint32_t flags)</p><p style="margin:0;">>  <span style="white-space:pre">       </span>resource_size_t aper_size;</p><p style="margin:0;">>  <span style="white-space:pre"> </span>resource_size_t mmio_base;</p><p style="margin:0;">>  <span style="white-space:pre"> </span>resource_size_t mmio_size;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>u32 ret;</p><p style="margin:0;">>  </p><p style="margin:0;">>  <span style="white-space:pre">    </span>/* GPU MEM */</p><p style="margin:0;">>  <span style="white-space:pre">      </span>/* We need get 7A-gpu pci device information for ldev->gpu_pdev */</p><p style="margin:0;">> @@ -72,6 +74,18 @@ static int loongson_device_init(struct drm_device *dev, uint32_t flags)</p><p style="margin:0;">>  <span style="white-space:pre">        </span>if (ldev->io == NULL)</p><p style="margin:0;">>  <span style="white-space:pre">           </span>return -ENOMEM;</p><p style="margin:0;">>  </p><p style="margin:0;">> +<span style="white-space:pre">  </span>ret = loongson_dc_gpio_init(ldev);</p><p style="margin:0;">> +<span style="white-space:pre">      </span>if (ret) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>DRM_ERROR("Failed to initialize dc gpios\n");</p><p style="margin:0;">> +<span style="white-space:pre">         </span>return ret;</p><p style="margin:0;">> +<span style="white-space:pre">     </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>ret = loongson_i2c_init(ldev);</p><p style="margin:0;">> +<span style="white-space:pre">  </span>if (ret) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>DRM_ERROR("Failed to initialize dc i2c\n");</p><p style="margin:0;">> +<span style="white-space:pre">           </span>return ret;</p><p style="margin:0;">> +<span style="white-space:pre">     </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">>  <span style="white-space:pre">     </span>DRM_INFO("DC mmio base 0x%llx size 0x%llx io 0x%llx\n",</p><p style="margin:0;">>  <span style="white-space:pre">          </span> mmio_base, mmio_size, *(u64 *)ldev->io);</p><p style="margin:0;">>  <span style="white-space:pre">       </span>DRM_INFO("GPU vram start = 0x%x size = 0x%x\n",</p><p style="margin:0;">> diff --git a/drivers/gpu/drm/loongson/loongson_drv.h b/drivers/gpu/drm/loongson/loongson_drv.h</p><p style="margin:0;">> index 498d1b082..24a534c3c 100644</p><p style="margin:0;">> --- a/drivers/gpu/drm/loongson/loongson_drv.h</p><p style="margin:0;">> +++ b/drivers/gpu/drm/loongson/loongson_drv.h</p><p style="margin:0;">> @@ -18,6 +18,7 @@</p><p style="margin:0;">>  #include <drm/drm_crtc_helper.h></p><p style="margin:0;">>  #include <drm/drm_connector.h></p><p style="margin:0;">>  #include <drm/drm_encoder.h></p><p style="margin:0;">> +#include "loongson_i2c.h"</p><p style="margin:0;">>  </p><p style="margin:0;">>  /* General customization:</p><p style="margin:0;">>   */</p><p style="margin:0;">> @@ -28,6 +29,7 @@</p><p style="margin:0;">>  </p><p style="margin:0;">>  #define to_loongson_crtc(x) container_of(x, struct loongson_crtc, base)</p><p style="margin:0;">>  #define to_loongson_encoder(x) container_of(x, struct loongson_encoder, base)</p><p style="margin:0;">> +#define to_loongson_connector(x) container_of(x, struct loongson_connector, base)</p><p style="margin:0;">>  </p><p style="margin:0;">>  #define LS7A_CHIPCFG_REG_BASE (0x10010000)</p><p style="margin:0;">>  #define PCI_DEVICE_ID_LOONGSON_DC 0x7a06</p><p style="margin:0;">> @@ -92,8 +94,10 @@ struct loongson_encoder {</p><p style="margin:0;">>  struct loongson_connector {</p><p style="margin:0;">>  <span style="white-space:pre">  </span>struct drm_connector base;</p><p style="margin:0;">>  <span style="white-space:pre"> </span>struct loongson_device *ldev;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>struct loongson_i2c *i2c;</p><p style="margin:0;">>  <span style="white-space:pre">  </span>u16 id;</p><p style="margin:0;">>  <span style="white-space:pre">    </span>u32 type;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>u16 i2c_id;</p><p style="margin:0;">>  };</p><p style="margin:0;">>  </p><p style="margin:0;">>  struct loongson_mode_info {</p><p style="margin:0;">> @@ -115,6 +119,9 @@ struct loongson_device {</p><p style="margin:0;">>  <span style="white-space:pre">        </span>u32 num_crtc;</p><p style="margin:0;">>  <span style="white-space:pre">      </span>struct loongson_mode_info mode_info[2];</p><p style="margin:0;">>  <span style="white-space:pre">    </span>struct pci_dev *gpu_pdev; /* LS7A gpu device info */</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">       </span>struct loongson_i2c i2c_bus[LS_MAX_I2C_BUS];</p><p style="margin:0;">> +<span style="white-space:pre">    </span>struct gpio_chip chip;</p><p style="margin:0;">>  };</p><p style="margin:0;">>  </p><p style="margin:0;">>  /* crtc */</p><p style="margin:0;">> @@ -129,6 +136,9 @@ int loongson_encoder_init(struct loongson_device *ldev, int index);</p><p style="margin:0;">>  /* plane */</p><p style="margin:0;">>  int loongson_plane_init(struct loongson_crtc *lcrtc);</p><p style="margin:0;">>  </p><p style="margin:0;">> +/* i2c */</p><p style="margin:0;">> +int loongson_dc_gpio_init(struct loongson_device *ldev);</p><p style="margin:0;">> +</p><p style="margin:0;">>  /* device */</p><p style="margin:0;">>  u32 loongson_gpu_offset(struct drm_plane_state *state);</p><p style="margin:0;">>  u32 ls7a_mm_rreg(struct loongson_device *ldev, u32 offset);</p><p style="margin:0;">> diff --git a/drivers/gpu/drm/loongson/loongson_i2c.c b/drivers/gpu/drm/loongson/loongson_i2c.c</p><p style="margin:0;">> new file mode 100644</p><p style="margin:0;">> index 000000000..b34c9e3c4</p><p style="margin:0;">> --- /dev/null</p><p style="margin:0;">> +++ b/drivers/gpu/drm/loongson/loongson_i2c.c</p><p style="margin:0;">> @@ -0,0 +1,264 @@</p><p style="margin:0;">> +// SPDX-License-Identifier: GPL-2.0-or-later</p><p style="margin:0;">> +</p><p style="margin:0;">> +#include "loongson_i2c.h"</p><p style="margin:0;">> +#include "loongson_drv.h"</p><p style="margin:0;">> +#include "linux/gpio.h"</p><p style="margin:0;">> +#include <linux/gpio/consumer.h></p><p style="margin:0;">> +</p><p style="margin:0;">> +static struct gpio i2c_gpios[4] = {</p><p style="margin:0;">> +<span style="white-space:pre">      </span>{ .gpio = DC_GPIO_0, .flags = GPIOF_OPEN_DRAIN, .label = "i2c-6-sda" },</p><p style="margin:0;">> +<span style="white-space:pre">       </span>{ .gpio = DC_GPIO_1, .flags = GPIOF_OPEN_DRAIN, .label = "i2c-6-scl" },</p><p style="margin:0;">> +<span style="white-space:pre">       </span>{ .gpio = DC_GPIO_2, .flags = GPIOF_OPEN_DRAIN, .label = "i2c-7-sda" },</p><p style="margin:0;">> +<span style="white-space:pre">       </span>{ .gpio = DC_GPIO_3, .flags = GPIOF_OPEN_DRAIN, .label = "i2c-7-scl" },</p><p style="margin:0;">> +};</p><p style="margin:0;">> +</p><p style="margin:0;">> +static inline void __dc_gpio_set_dir(struct loongson_device *ldev, unsigned int pin, int input)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre"> </span>u32 temp;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>temp = ls_mm_rreg_locked(ldev, LS7A_DC_GPIO_CFG_OFFSET);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>if (input)</p><p style="margin:0;">> +<span style="white-space:pre">              </span>temp |= 1UL << pin;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>else</p><p style="margin:0;">> +<span style="white-space:pre">            </span>temp &= ~(1UL << pin);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>ls_mm_wreg_locked(ldev, LS7A_DC_GPIO_CFG_OFFSET, temp);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static void __dc_gpio_set_val(struct loongson_device *ldev, unsigned int pin, int high)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">    </span>u32 temp;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>temp = ls_mm_rreg_locked(ldev, LS7A_DC_GPIO_OUT_OFFSET);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>if (high)</p><p style="margin:0;">> +<span style="white-space:pre">               </span>temp |= 1UL << pin;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>else</p><p style="margin:0;">> +<span style="white-space:pre">            </span>temp &= ~(1UL << pin);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>ls_mm_wreg_locked(ldev, LS7A_DC_GPIO_OUT_OFFSET, temp);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int ls_dc_gpio_request(struct gpio_chip *chip, unsigned int pin)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">    </span>if (pin >= (chip->ngpio + chip->base))</p><p style="margin:0;">> +<span style="white-space:pre">         </span>return -EINVAL;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>else</p><p style="margin:0;">> +<span style="white-space:pre">            </span>return 0;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int ls_dc_gpio_dir_input(struct gpio_chip *chip, unsigned int pin)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct loongson_device *ldev;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">      </span>ldev = container_of(chip, struct loongson_device, chip);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>__dc_gpio_set_dir(ldev, pin, 1);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">   </span>return 0;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int ls_dc_gpio_dir_output(struct gpio_chip *chip, unsigned int pin, int value)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">    </span>struct loongson_device *ldev;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">      </span>ldev = container_of(chip, struct loongson_device, chip);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>__dc_gpio_set_val(ldev, pin, value);</p><p style="margin:0;">> +<span style="white-space:pre">    </span>__dc_gpio_set_dir(ldev, pin, 0);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">   </span>return 0;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static void ls_dc_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">  </span>struct loongson_device *ldev;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">      </span>ldev = container_of(chip, struct loongson_device, chip);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>__dc_gpio_set_val(ldev, pin, value);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int ls_dc_gpio_get(struct gpio_chip *chip, unsigned int pin)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">   </span>u32 val;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct loongson_device *ldev;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">      </span>ldev = container_of(chip, struct loongson_device, chip);</p><p style="margin:0;">> +<span style="white-space:pre">        </span>val = ls_mm_rreg_locked(ldev, LS7A_DC_GPIO_IN_OFFSET);</p><p style="margin:0;">> +<span style="white-space:pre">  </span>return (val >> pin) & 1;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static void loongson_i2c_set_data(void *i2c, int value)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre"> </span>struct loongson_i2c *li2c = i2c;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct gpio_desc *gpiod = gpio_to_desc(i2c_gpios[li2c->data].gpio);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">     </span>gpiod_set_value_cansleep(gpiod, value);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static void loongson_i2c_set_clock(void *i2c, int value)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">   </span>struct loongson_i2c *li2c = i2c;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct gpio_desc *gpiod = gpio_to_desc(i2c_gpios[li2c->clock].gpio);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">    </span>gpiod_set_value_cansleep(gpiod, value);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int loongson_i2c_get_data(void *i2c)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct loongson_i2c *li2c = i2c;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct gpio_desc *gpiod = gpio_to_desc(i2c_gpios[li2c->data].gpio);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">     </span>return gpiod_get_value_cansleep(gpiod);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int loongson_i2c_get_clock(void *i2c)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">       </span>struct loongson_i2c *li2c = i2c;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct gpio_desc *gpiod = gpio_to_desc(i2c_gpios[li2c->clock].gpio);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">    </span>return gpiod_get_value_cansleep(gpiod);</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int loongson_i2c_create(struct loongson_i2c *li2c, const char *name)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">        </span>int ret;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>unsigned int i2c_num;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>struct i2c_client *i2c_cli;</p><p style="margin:0;">> +<span style="white-space:pre">     </span>struct i2c_adapter *i2c_adapter;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct i2c_board_info i2c_info;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>struct i2c_algo_bit_data *i2c_algo_data;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct device *dev;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">        </span>dev = &li2c->adapter->dev;</p><p style="margin:0;">> +<span style="white-space:pre">    </span>i2c_num = li2c->i2c_id;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>i2c_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);</p><p style="margin:0;">> +<span style="white-space:pre">  </span>if (IS_ERR(i2c_adapter)) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>ret = PTR_ERR(i2c_adapter);</p><p style="margin:0;">> +<span style="white-space:pre">             </span>goto error_mem;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>}</p><p style="margin:0;">> +<span style="white-space:pre">       </span>i2c_algo_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);</p><p style="margin:0;">> +<span style="white-space:pre">  </span>if (IS_ERR(i2c_algo_data)) {</p><p style="margin:0;">> +<span style="white-space:pre">            </span>ret = PTR_ERR(i2c_algo_data);</p><p style="margin:0;">> +<span style="white-space:pre">           </span>goto error_mem;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>i2c_adapter->owner = THIS_MODULE;</p><p style="margin:0;">> +<span style="white-space:pre">    </span>i2c_adapter->class = I2C_CLASS_DDC;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>i2c_adapter->algo_data = i2c_algo_data;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>i2c_adapter->nr = i2c_num;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>snprintf(i2c_adapter->name, sizeof(i2c_adapter->name), "%s%d", name, i2c_num - DC_I2C_BASE);</p><p style="margin:0;">> +<span style="white-space:pre">    </span>li2c->data = i2c_num % DC_I2C_BASE * 2;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>li2c->clock = i2c_num % DC_I2C_BASE * 2 + 1;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>DRM_INFO("Created i2c-%d, sda=%d, scl=%d\n", i2c_num, li2c->data, li2c->clock);</p><p style="margin:0;">> +<span style="white-space:pre"> </span>if (gpio_cansleep(i2c_gpios[li2c->data].gpio) || gpio_cansleep(i2c_gpios[li2c->clock].gpio))</p><p style="margin:0;">> +<span style="white-space:pre">              </span>dev_warn(dev, "Slow GPIO pins might wreak havoc I2C timing\n");</p><p style="margin:0;">> +<span style="white-space:pre">       </span>i2c_algo_data->setsda = loongson_i2c_set_data;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>i2c_algo_data->setscl = loongson_i2c_set_clock;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>i2c_algo_data->getsda = loongson_i2c_get_data;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>i2c_algo_data->getscl = loongson_i2c_get_clock;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>i2c_algo_data->udelay = DC_I2C_TON;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>i2c_algo_data->timeout = usecs_to_jiffies(2200); /* from VESA */</p><p style="margin:0;">> +<span style="white-space:pre">     </span>ret = i2c_bit_add_numbered_bus(i2c_adapter);</p><p style="margin:0;">> +<span style="white-space:pre">    </span>if (ret) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>DRM_ERROR("Failed to register i2c algo-bit adapter %s\n", i2c_adapter->name);</p><p style="margin:0;">> +<span style="white-space:pre">              </span>kfree(i2c_adapter);</p><p style="margin:0;">> +<span style="white-space:pre">             </span>i2c_adapter = NULL;</p><p style="margin:0;">> +<span style="white-space:pre">     </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>li2c->adapter = i2c_adapter;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>i2c_algo_data->data = li2c;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>i2c_set_adapdata(li2c->adapter, li2c);</p><p style="margin:0;">> +<span style="white-space:pre">       </span>DRM_INFO("Register i2c algo-bit adapter [%s]\n", i2c_adapter->name);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>memset(&i2c_info, 0, sizeof(struct i2c_board_info));</p><p style="margin:0;">> +<span style="white-space:pre">        </span>strncpy(i2c_info.type, name, I2C_NAME_SIZE);</p><p style="margin:0;">> +<span style="white-space:pre">    </span>i2c_info.addr = DDC_ADDR;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>i2c_cli = i2c_new_client_device(i2c_adapter, &i2c_info);</p><p style="margin:0;">> +<span style="white-space:pre">    </span>if (i2c_cli == NULL) {</p><p style="margin:0;">> +<span style="white-space:pre">          </span>DRM_ERROR("Failed to create i2c adapter\n");</p><p style="margin:0;">> +<span style="white-space:pre">          </span>return -EBUSY;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>}</p><p style="margin:0;">> +<span style="white-space:pre">       </span>li2c->init = true;</p><p style="margin:0;">> +<span style="white-space:pre">   </span>return 0;</p><p style="margin:0;">> +</p><p style="margin:0;">> +error_mem:</p><p style="margin:0;">> +<span style="white-space:pre">   </span>DRM_ERROR("Failed to malloc memory for loongson i2c\n");</p><p style="margin:0;">> +<span style="white-space:pre">      </span>return ret;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +static int loongson_i2c_add(struct loongson_device *ldev, const char *name)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">    </span>int i;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">     </span>for (i = 0; i < LS_MAX_I2C_BUS; i++) {</p><p style="margin:0;">> +<span style="white-space:pre">               </span>if (ldev->i2c_bus[i].use) {</p><p style="margin:0;">> +<span style="white-space:pre">                  </span>loongson_i2c_create(&ldev->i2c_bus[i], name);</p><p style="margin:0;">> +<span style="white-space:pre">            </span>} else {</p><p style="margin:0;">> +<span style="white-space:pre">                        </span>DRM_DEBUG_DRIVER("i2c_bus[%d] not use\n", i);</p><p style="margin:0;">> +<span style="white-space:pre">                 </span>return -ENODEV;</p><p style="margin:0;">> +<span style="white-space:pre">         </span>}</p><p style="margin:0;">> +<span style="white-space:pre">       </span>}</p><p style="margin:0;">> +<span style="white-space:pre">       </span>return 0;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +int loongson_dc_gpio_init(struct loongson_device *ldev)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">  </span>int ret;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>struct gpio_chip *chip;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">    </span>chip = &ldev->chip;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>chip->label = "ls7a-dc-gpio";</p><p style="margin:0;">> +<span style="white-space:pre">      </span>chip->base = LS7A_DC_GPIO_BASE;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>chip->ngpio = 4;</p><p style="margin:0;">> +<span style="white-space:pre">     </span>chip->parent = ldev->dev->dev;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>chip->request = ls_dc_gpio_request;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>chip->direction_input = ls_dc_gpio_dir_input;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>chip->direction_output = ls_dc_gpio_dir_output;</p><p style="margin:0;">> +<span style="white-space:pre">      </span>chip->set = ls_dc_gpio_set;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>chip->get = ls_dc_gpio_get;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>chip->can_sleep = false;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">        </span>ret = devm_gpiochip_add_data(ldev->dev->dev, chip, ldev);</p><p style="margin:0;">> +<span style="white-space:pre"> </span>if (ret) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>DRM_ERROR("Failed to register ls7a dc gpio driver\n");</p><p style="margin:0;">> +<span style="white-space:pre">                </span>return -ENODEV;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>}</p><p style="margin:0;">> +<span style="white-space:pre">       </span>DRM_INFO("Registered ls7a dc gpio driver\n");</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">    </span>return 0;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +int loongson_i2c_init(struct loongson_device *ldev)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">      </span>int ret;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">   </span>ret = gpio_request_array(i2c_gpios, ARRAY_SIZE(i2c_gpios));</p><p style="margin:0;">> +<span style="white-space:pre">     </span>if (ret) {</p><p style="margin:0;">> +<span style="white-space:pre">              </span>DRM_ERROR("Failed to request gpio array i2c_gpios\n");</p><p style="margin:0;">> +<span style="white-space:pre">                </span>return -ENODEV;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>ldev->i2c_bus[0].i2c_id = 6;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>ldev->i2c_bus[0].use = true;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>ldev->i2c_bus[1].i2c_id = 7;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>ldev->i2c_bus[1].use = true;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">    </span>loongson_i2c_add(ldev, DC_I2C_NAME);</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">       </span>return 0;</p><p style="margin:0;">> +}</p><p style="margin:0;">> +</p><p style="margin:0;">> +struct loongson_i2c *loongson_i2c_bus_match(struct loongson_device *ldev, u32 i2c_id)</p><p style="margin:0;">> +{</p><p style="margin:0;">> +<span style="white-space:pre">    </span>u32 i;</p><p style="margin:0;">> +<span style="white-space:pre">  </span>struct loongson_i2c *match = NULL, *tables;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">        </span>tables = ldev->i2c_bus;</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre"> </span>for (i = 0; i < LS_MAX_I2C_BUS; i++) {</p><p style="margin:0;">> +<span style="white-space:pre">               </span>if (tables->i2c_id == i2c_id && tables->init == true) {</p><p style="margin:0;">> +<span style="white-space:pre">                   </span>match = tables;</p><p style="margin:0;">> +<span style="white-space:pre">                 </span>break;</p><p style="margin:0;">> +<span style="white-space:pre">          </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">          </span>tables++;</p><p style="margin:0;">> +<span style="white-space:pre">       </span>}</p><p style="margin:0;">> +</p><p style="margin:0;">> +<span style="white-space:pre">  </span>return match;</p><p style="margin:0;">> +}</p><p style="margin:0;">> diff --git a/drivers/gpu/drm/loongson/loongson_i2c.h b/drivers/gpu/drm/loongson/loongson_i2c.h</p><p style="margin:0;">> new file mode 100644</p><p style="margin:0;">> index 000000000..164619007</p><p style="margin:0;">> --- /dev/null</p><p style="margin:0;">> +++ b/drivers/gpu/drm/loongson/loongson_i2c.h</p><p style="margin:0;">> @@ -0,0 +1,40 @@</p><p style="margin:0;">> +/* SPDX-License-Identifier: GPL-2.0-only */</p><p style="margin:0;">> +</p><p style="margin:0;">> +#ifndef __LOONGSON_I2C_H__</p><p style="margin:0;">> +#define __LOONGSON_I2C_H__</p><p style="margin:0;">> +</p><p style="margin:0;">> +#include <linux/i2c.h></p><p style="margin:0;">> +#include <linux/i2c-algo-bit.h></p><p style="margin:0;">> +#include <linux/gpio/driver.h></p><p style="margin:0;">> +#include <drm/drm_edid.h></p><p style="margin:0;">> +</p><p style="margin:0;">> +// Modify this marco to config i2c bus speed, bus_freq = 500 / T</p><p style="margin:0;">> +// Eg: i2c_bus_freq=100k when T=5</p><p style="margin:0;">> +#define DC_I2C_TON 5</p><p style="margin:0;">> +#define DC_I2C_BASE 6</p><p style="margin:0;">> +#define DC_I2C_NAME "ls_dc_i2c"</p><p style="margin:0;">> +#define LS_MAX_I2C_BUS 16</p><p style="margin:0;">> +</p><p style="margin:0;">> +/* Loongson 7A display controller proprietary GPIOs */</p><p style="margin:0;">> +#define LS7A_DC_GPIO_BASE 73</p><p style="margin:0;">> +#define DC_GPIO_0 (73)</p><p style="margin:0;">> +#define DC_GPIO_1 (74)</p><p style="margin:0;">> +#define DC_GPIO_2 (75)</p><p style="margin:0;">> +#define DC_GPIO_3 (76)</p><p style="margin:0;">> +#define LS7A_DC_GPIO_CFG_OFFSET (0x1660)</p><p style="margin:0;">> +#define LS7A_DC_GPIO_IN_OFFSET (0x1650)</p><p style="margin:0;">> +#define LS7A_DC_GPIO_OUT_OFFSET (0x1650)</p><p style="margin:0;">> +</p><p style="margin:0;">> +struct loongson_device;</p><p style="margin:0;">> +struct loongson_i2c {</p><p style="margin:0;">> +<span style="white-space:pre">  </span>struct i2c_adapter *adapter;</p><p style="margin:0;">> +<span style="white-space:pre">    </span>u32 data, clock;</p><p style="margin:0;">> +<span style="white-space:pre">        </span>bool use, init;</p><p style="margin:0;">> +<span style="white-space:pre"> </span>u32 i2c_id;</p><p style="margin:0;">> +};</p><p style="margin:0;">> +</p><p style="margin:0;">> +struct loongson_i2c *loongson_i2c_bus_match(struct loongson_device *ldev,</p><p style="margin:0;">> +<span style="white-space:pre">                                   </span>    u32 i2c_id);</p><p style="margin:0;">> +int loongson_i2c_init(struct loongson_device *ldev);</p><p style="margin:0;">> +</p><p style="margin:0;">> +#endif /* __LOONGSON_I2C_H__ */</p><p style="margin:0;">> -- </p><p style="margin:0;">> 2.27.0</p><p style="margin:0;"><br></p><p style="margin:0;"><br></p><p style="margin:0;">------------------------------</p><p style="margin:0;">Loongson LiChenyang</p></div><br><br><span title="neteasefooter"><p> </p></span>