[PATCH 4/4] drm/dp: Allow registering AUX channels as I2C busses
Thierry Reding
thierry.reding at gmail.com
Thu Dec 12 06:53:50 PST 2013
This reuses the existing I2C-over-AUX implementation by translating the
messages to ones compatible with the struct drm_dp_aux implementation.
Signed-off-by: Thierry Reding <treding at nvidia.com>
---
drivers/gpu/drm/drm_dp_helper.c | 78 +++++++++++++++++++++++++++++++++++++++++
include/drm/drm_dp_helper.h | 4 +++
2 files changed, 82 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 873aedccc84e..2864a47e6abe 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -471,3 +471,81 @@ int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
return 0;
}
+
+struct drm_dp_i2c_adapter {
+ struct i2c_algo_dp_aux_data algo;
+ struct i2c_adapter adapter;
+ struct drm_dp_aux *aux;
+};
+
+static int drm_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
+ uint8_t write_byte, uint8_t *read_byte)
+{
+ struct drm_dp_i2c_adapter *dp = container_of(adapter, struct drm_dp_i2c_adapter, adapter);
+ struct i2c_algo_dp_aux_data *algo = adapter->algo_data;
+ struct drm_dp_aux_msg msg;
+ u8 data = 0;
+ int err;
+
+ if (mode & MODE_I2C_START)
+ return 0;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.address = algo->address;
+ msg.flags = DRM_DP_AUX_I2C;
+
+ if ((mode & MODE_I2C_STOP) == 0)
+ msg.flags |= DRM_DP_AUX_I2C_MOT;
+
+ if (mode & MODE_I2C_WRITE) {
+ msg.flags |= DRM_DP_AUX_WRITE;
+ msg.buffer = &write_byte;
+ msg.size = 1;
+ } else {
+ msg.buffer = &data;
+ msg.size = 1;
+ }
+
+ err = dp->aux->transfer(dp->aux, &msg);
+ if (err < 0)
+ return err;
+
+ /*
+ * Allow the transfer() functions to be ignorant about whether or not
+ * the read buffer passed in is valid or not.
+ */
+ if (((mode & MODE_I2C_WRITE) == 0) && read_byte)
+ *read_byte = data;
+
+ return err;
+}
+
+struct i2c_adapter *drm_dp_add_i2c_bus(struct drm_dp_aux *aux)
+{
+ struct drm_dp_i2c_adapter *adapter;
+ int err;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return ERR_PTR(-ENOMEM);
+
+ adapter->algo.running = false;
+ adapter->algo.address = 0;
+ adapter->algo.aux_ch = drm_dp_i2c_aux_ch;
+ adapter->aux = aux;
+
+ adapter->adapter.class = I2C_CLASS_DDC;
+ adapter->adapter.owner = THIS_MODULE;
+ strncpy(adapter->adapter.name, "DPAUX", sizeof(adapter->adapter.name));
+ adapter->adapter.algo_data = &adapter->algo;
+ adapter->adapter.dev.parent = aux->dev;
+ adapter->adapter.dev.of_node = aux->dev->of_node;
+
+ err = i2c_dp_aux_add_bus(&adapter->adapter);
+ if (err < 0) {
+ kfree(adapter);
+ return ERR_PTR(err);
+ }
+
+ return &adapter->adapter;
+}
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index cf03a6ff8634..8b0f6c44251e 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -444,6 +444,8 @@ struct drm_dp_aux_msg {
* @transfer: transfers a message representing a single AUX transaction
*/
struct drm_dp_aux {
+ struct device *dev;
+
ssize_t (*transfer)(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg);
};
@@ -515,4 +517,6 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
*/
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
+struct i2c_adapter *drm_dp_add_i2c_bus(struct drm_dp_aux *aux);
+
#endif /* _DRM_DP_HELPER_H_ */
--
1.8.4.2
More information about the dri-devel
mailing list