aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchit Taneja <architt@codeaurora.org>2016-06-15 07:31:27 -0400
committerArchit Taneja <architt@codeaurora.org>2016-07-13 04:54:37 -0400
commit1e4d58cd7f888522d16f221d628356befbb08468 (patch)
tree9b3522f349f458ab29374c639352781caad81246
parent2437e7cd88e8781cef5fd2c254c85aa62b305d04 (diff)
drm/bridge: adv7533: Create a MIPI DSI device
In order to pass DSI specific parameters to the DSI host, we need the driver to create a mipi_dsi_device DSI device that attaches to the host. Use of_graph helpers to get the DSI host DT node. Create a MIPI DSI device using this host. Finally, attach this device to the DSI host. Populate DT parameters (number of data lanes for now) that are required for DSI RX to work correctly. Hardcode few other parameters (rgb, embedded_sync) for now. Select DRM_MIPI_DSI config option only when ADV7533 support is enabled. Signed-off-by: Archit Taneja <architt@codeaurora.org>
-rw-r--r--drivers/gpu/drm/bridge/adv7511/Kconfig1
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511.h23
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c40
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7533.c91
4 files changed, 147 insertions, 8 deletions
diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
index eb844199d148..d2b0499ab7d7 100644
--- a/drivers/gpu/drm/bridge/adv7511/Kconfig
+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
@@ -9,6 +9,7 @@ config DRM_I2C_ADV7511
9config DRM_I2C_ADV7533 9config DRM_I2C_ADV7533
10 bool "ADV7533 encoder" 10 bool "ADV7533 encoder"
11 depends on DRM_I2C_ADV7511 11 depends on DRM_I2C_ADV7511
12 select DRM_MIPI_DSI
12 default y 13 default y
13 help 14 help
14 Support for the Analog Devices ADV7533 DSI to HDMI encoder. 15 Support for the Analog Devices ADV7533 DSI to HDMI encoder.
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 5dea769c3c71..3e4d47a3124a 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -14,6 +14,7 @@
14#include <linux/regmap.h> 14#include <linux/regmap.h>
15 15
16#include <drm/drm_crtc_helper.h> 16#include <drm/drm_crtc_helper.h>
17#include <drm/drm_mipi_dsi.h>
17 18
18#define ADV7511_REG_CHIP_REVISION 0x00 19#define ADV7511_REG_CHIP_REVISION 0x00
19#define ADV7511_REG_N0 0x01 20#define ADV7511_REG_N0 0x01
@@ -324,6 +325,11 @@ struct adv7511 {
324 325
325 struct gpio_desc *gpio_pd; 326 struct gpio_desc *gpio_pd;
326 327
328 /* ADV7533 DSI RX related params */
329 struct device_node *host_node;
330 struct mipi_dsi_device *dsi;
331 u8 num_dsi_lanes;
332
327 enum adv7511_type type; 333 enum adv7511_type type;
328}; 334};
329 335
@@ -333,6 +339,9 @@ void adv7533_dsi_power_off(struct adv7511 *adv);
333int adv7533_patch_registers(struct adv7511 *adv); 339int adv7533_patch_registers(struct adv7511 *adv);
334void adv7533_uninit_cec(struct adv7511 *adv); 340void adv7533_uninit_cec(struct adv7511 *adv);
335int adv7533_init_cec(struct adv7511 *adv); 341int adv7533_init_cec(struct adv7511 *adv);
342int adv7533_attach_dsi(struct adv7511 *adv);
343void adv7533_detach_dsi(struct adv7511 *adv);
344int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
336#else 345#else
337static inline void adv7533_dsi_power_on(struct adv7511 *adv) 346static inline void adv7533_dsi_power_on(struct adv7511 *adv)
338{ 347{
@@ -355,6 +364,20 @@ static inline int adv7533_init_cec(struct adv7511 *adv)
355{ 364{
356 return -ENODEV; 365 return -ENODEV;
357} 366}
367
368static inline int adv7533_attach_dsi(struct adv7511 *adv)
369{
370 return -ENODEV;
371}
372
373static inline void adv7533_detach_dsi(struct adv7511 *adv)
374{
375}
376
377static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
378{
379 return -ENODEV;
380}
358#endif 381#endif
359 382
360#endif /* __DRM_I2C_ADV7511_H__ */ 383#endif /* __DRM_I2C_ADV7511_H__ */
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index e33702bbd5d5..6586c5220842 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -817,6 +817,9 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
817 &adv7511_connector_helper_funcs); 817 &adv7511_connector_helper_funcs);
818 drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder); 818 drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
819 819
820 if (adv->type == ADV7533)
821 ret = adv7533_attach_dsi(adv);
822
820 return ret; 823 return ret;
821} 824}
822 825
@@ -943,11 +946,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
943 946
944 memset(&link_config, 0, sizeof(link_config)); 947 memset(&link_config, 0, sizeof(link_config));
945 948
946 if (adv7511->type == ADV7511) { 949 if (adv7511->type == ADV7511)
947 ret = adv7511_parse_dt(dev->of_node, &link_config); 950 ret = adv7511_parse_dt(dev->of_node, &link_config);
948 if (ret) 951 else
949 return ret; 952 ret = adv7533_parse_dt(dev->of_node, adv7511);
950 } 953 if (ret)
954 return ret;
951 955
952 /* 956 /*
953 * The power down GPIO is optional. If present, toggle it from active to 957 * The power down GPIO is optional. If present, toggle it from active to
@@ -1042,9 +1046,13 @@ static int adv7511_remove(struct i2c_client *i2c)
1042{ 1046{
1043 struct adv7511 *adv7511 = i2c_get_clientdata(i2c); 1047 struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
1044 1048
1049 if (adv7511->type == ADV7533) {
1050 adv7533_detach_dsi(adv7511);
1051 adv7533_uninit_cec(adv7511);
1052 }
1053
1045 drm_bridge_remove(&adv7511->bridge); 1054 drm_bridge_remove(&adv7511->bridge);
1046 1055
1047 adv7533_uninit_cec(adv7511);
1048 i2c_unregister_device(adv7511->i2c_edid); 1056 i2c_unregister_device(adv7511->i2c_edid);
1049 1057
1050 kfree(adv7511->edid); 1058 kfree(adv7511->edid);
@@ -1074,6 +1082,10 @@ static const struct of_device_id adv7511_of_ids[] = {
1074}; 1082};
1075MODULE_DEVICE_TABLE(of, adv7511_of_ids); 1083MODULE_DEVICE_TABLE(of, adv7511_of_ids);
1076 1084
1085static struct mipi_dsi_driver adv7533_dsi_driver = {
1086 .driver.name = "adv7533",
1087};
1088
1077static struct i2c_driver adv7511_driver = { 1089static struct i2c_driver adv7511_driver = {
1078 .driver = { 1090 .driver = {
1079 .name = "adv7511", 1091 .name = "adv7511",
@@ -1084,7 +1096,23 @@ static struct i2c_driver adv7511_driver = {
1084 .remove = adv7511_remove, 1096 .remove = adv7511_remove,
1085}; 1097};
1086 1098
1087module_i2c_driver(adv7511_driver); 1099static int __init adv7511_init(void)
1100{
1101 if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
1102 mipi_dsi_driver_register(&adv7533_dsi_driver);
1103
1104 return i2c_add_driver(&adv7511_driver);
1105}
1106module_init(adv7511_init);
1107
1108static void __exit adv7511_exit(void)
1109{
1110 i2c_del_driver(&adv7511_driver);
1111
1112 if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
1113 mipi_dsi_driver_unregister(&adv7533_dsi_driver);
1114}
1115module_exit(adv7511_exit);
1088 1116
1089MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1117MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
1090MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver"); 1118MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index cb4ca640a2b3..ecbcaa010931 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -11,6 +11,8 @@
11 * GNU General Public License for more details. 11 * GNU General Public License for more details.
12 */ 12 */
13 13
14#include <linux/of_graph.h>
15
14#include "adv7511.h" 16#include "adv7511.h"
15 17
16static const struct reg_sequence adv7533_fixed_registers[] = { 18static const struct reg_sequence adv7533_fixed_registers[] = {
@@ -39,8 +41,10 @@ static const struct regmap_config adv7533_cec_regmap_config = {
39 41
40void adv7533_dsi_power_on(struct adv7511 *adv) 42void adv7533_dsi_power_on(struct adv7511 *adv)
41{ 43{
42 /* set number of dsi lanes (hardcoded to 4 for now) */ 44 struct mipi_dsi_device *dsi = adv->dsi;
43 regmap_write(adv->regmap_cec, 0x1c, 4 << 4); 45
46 /* set number of dsi lanes */
47 regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
44 /* disable internal timing generator */ 48 /* disable internal timing generator */
45 regmap_write(adv->regmap_cec, 0x27, 0x0b); 49 regmap_write(adv->regmap_cec, 0x27, 0x0b);
46 /* enable hdmi */ 50 /* enable hdmi */
@@ -98,3 +102,86 @@ err:
98 adv7533_uninit_cec(adv); 102 adv7533_uninit_cec(adv);
99 return ret; 103 return ret;
100} 104}
105
106int adv7533_attach_dsi(struct adv7511 *adv)
107{
108 struct device *dev = &adv->i2c_main->dev;
109 struct mipi_dsi_host *host;
110 struct mipi_dsi_device *dsi;
111 int ret = 0;
112 const struct mipi_dsi_device_info info = { .type = "adv7533",
113 .channel = 0,
114 .node = NULL,
115 };
116
117 host = of_find_mipi_dsi_host_by_node(adv->host_node);
118 if (!host) {
119 dev_err(dev, "failed to find dsi host\n");
120 return -EPROBE_DEFER;
121 }
122
123 dsi = mipi_dsi_device_register_full(host, &info);
124 if (IS_ERR(dsi)) {
125 dev_err(dev, "failed to create dsi device\n");
126 ret = PTR_ERR(dsi);
127 goto err_dsi_device;
128 }
129
130 adv->dsi = dsi;
131
132 dsi->lanes = adv->num_dsi_lanes;
133 dsi->format = MIPI_DSI_FMT_RGB888;
134 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
135 MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
136
137 ret = mipi_dsi_attach(dsi);
138 if (ret < 0) {
139 dev_err(dev, "failed to attach dsi to host\n");
140 goto err_dsi_attach;
141 }
142
143 return 0;
144
145err_dsi_attach:
146 mipi_dsi_device_unregister(dsi);
147err_dsi_device:
148 return ret;
149}
150
151void adv7533_detach_dsi(struct adv7511 *adv)
152{
153 mipi_dsi_detach(adv->dsi);
154 mipi_dsi_device_unregister(adv->dsi);
155}
156
157int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
158{
159 u32 num_lanes;
160 struct device_node *endpoint;
161
162 of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
163
164 if (num_lanes < 1 || num_lanes > 4)
165 return -EINVAL;
166
167 adv->num_dsi_lanes = num_lanes;
168
169 endpoint = of_graph_get_next_endpoint(np, NULL);
170 if (!endpoint)
171 return -ENODEV;
172
173 adv->host_node = of_graph_get_remote_port_parent(endpoint);
174 if (!adv->host_node) {
175 of_node_put(endpoint);
176 return -ENODEV;
177 }
178
179 of_node_put(endpoint);
180 of_node_put(adv->host_node);
181
182 /* TODO: Check if these need to be parsed by DT or not */
183 adv->rgb = true;
184 adv->embedded_sync = false;
185
186 return 0;
187}