2 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <linux/of_graph.h>
18 static const struct reg_sequence adv7533_fixed_registers
[] = {
27 static const struct reg_sequence adv7533_cec_fixed_registers
[] = {
34 static const struct regmap_config adv7533_cec_regmap_config
= {
39 .cache_type
= REGCACHE_RBTREE
,
42 static void adv7511_dsi_config_timing_gen(struct adv7511
*adv
)
44 struct mipi_dsi_device
*dsi
= adv
->dsi
;
45 struct drm_display_mode
*mode
= &adv
->curr_mode
;
46 unsigned int hsw
, hfp
, hbp
, vsw
, vfp
, vbp
;
47 u8 clock_div_by_lanes
[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */
49 hsw
= mode
->hsync_end
- mode
->hsync_start
;
50 hfp
= mode
->hsync_start
- mode
->hdisplay
;
51 hbp
= mode
->htotal
- mode
->hsync_end
;
52 vsw
= mode
->vsync_end
- mode
->vsync_start
;
53 vfp
= mode
->vsync_start
- mode
->vdisplay
;
54 vbp
= mode
->vtotal
- mode
->vsync_end
;
56 /* set pixel clock divider mode */
57 regmap_write(adv
->regmap_cec
, 0x16,
58 clock_div_by_lanes
[dsi
->lanes
- 2] << 3);
60 /* horizontal porch params */
61 regmap_write(adv
->regmap_cec
, 0x28, mode
->htotal
>> 4);
62 regmap_write(adv
->regmap_cec
, 0x29, (mode
->htotal
<< 4) & 0xff);
63 regmap_write(adv
->regmap_cec
, 0x2a, hsw
>> 4);
64 regmap_write(adv
->regmap_cec
, 0x2b, (hsw
<< 4) & 0xff);
65 regmap_write(adv
->regmap_cec
, 0x2c, hfp
>> 4);
66 regmap_write(adv
->regmap_cec
, 0x2d, (hfp
<< 4) & 0xff);
67 regmap_write(adv
->regmap_cec
, 0x2e, hbp
>> 4);
68 regmap_write(adv
->regmap_cec
, 0x2f, (hbp
<< 4) & 0xff);
70 /* vertical porch params */
71 regmap_write(adv
->regmap_cec
, 0x30, mode
->vtotal
>> 4);
72 regmap_write(adv
->regmap_cec
, 0x31, (mode
->vtotal
<< 4) & 0xff);
73 regmap_write(adv
->regmap_cec
, 0x32, vsw
>> 4);
74 regmap_write(adv
->regmap_cec
, 0x33, (vsw
<< 4) & 0xff);
75 regmap_write(adv
->regmap_cec
, 0x34, vfp
>> 4);
76 regmap_write(adv
->regmap_cec
, 0x35, (vfp
<< 4) & 0xff);
77 regmap_write(adv
->regmap_cec
, 0x36, vbp
>> 4);
78 regmap_write(adv
->regmap_cec
, 0x37, (vbp
<< 4) & 0xff);
81 void adv7533_dsi_power_on(struct adv7511
*adv
)
83 struct mipi_dsi_device
*dsi
= adv
->dsi
;
85 if (adv
->use_timing_gen
)
86 adv7511_dsi_config_timing_gen(adv
);
88 /* set number of dsi lanes */
89 regmap_write(adv
->regmap_cec
, 0x1c, dsi
->lanes
<< 4);
91 if (adv
->use_timing_gen
) {
92 /* reset internal timing generator */
93 regmap_write(adv
->regmap_cec
, 0x27, 0xcb);
94 regmap_write(adv
->regmap_cec
, 0x27, 0x8b);
95 regmap_write(adv
->regmap_cec
, 0x27, 0xcb);
97 /* disable internal timing generator */
98 regmap_write(adv
->regmap_cec
, 0x27, 0x0b);
102 regmap_write(adv
->regmap_cec
, 0x03, 0x89);
103 /* disable test mode */
104 regmap_write(adv
->regmap_cec
, 0x55, 0x00);
106 regmap_register_patch(adv
->regmap_cec
, adv7533_cec_fixed_registers
,
107 ARRAY_SIZE(adv7533_cec_fixed_registers
));
110 void adv7533_dsi_power_off(struct adv7511
*adv
)
113 regmap_write(adv
->regmap_cec
, 0x03, 0x0b);
114 /* disable internal timing generator */
115 regmap_write(adv
->regmap_cec
, 0x27, 0x0b);
118 void adv7533_mode_set(struct adv7511
*adv
, struct drm_display_mode
*mode
)
120 struct mipi_dsi_device
*dsi
= adv
->dsi
;
123 if (adv
->num_dsi_lanes
!= 4)
126 if (mode
->clock
> 80000)
131 if (lanes
!= dsi
->lanes
) {
132 mipi_dsi_detach(dsi
);
134 ret
= mipi_dsi_attach(dsi
);
136 dev_err(&dsi
->dev
, "failed to change host lanes\n");
140 int adv7533_patch_registers(struct adv7511
*adv
)
142 return regmap_register_patch(adv
->regmap
,
143 adv7533_fixed_registers
,
144 ARRAY_SIZE(adv7533_fixed_registers
));
147 void adv7533_uninit_cec(struct adv7511
*adv
)
149 i2c_unregister_device(adv
->i2c_cec
);
152 int adv7533_init_cec(struct adv7511
*adv
)
156 adv
->i2c_cec
= i2c_new_dummy(adv
->i2c_main
->adapter
,
157 adv
->i2c_main
->addr
- 1);
161 adv
->regmap_cec
= devm_regmap_init_i2c(adv
->i2c_cec
,
162 &adv7533_cec_regmap_config
);
163 if (IS_ERR(adv
->regmap_cec
)) {
164 ret
= PTR_ERR(adv
->regmap_cec
);
168 ret
= regmap_register_patch(adv
->regmap_cec
,
169 adv7533_cec_fixed_registers
,
170 ARRAY_SIZE(adv7533_cec_fixed_registers
));
176 adv7533_uninit_cec(adv
);
180 int adv7533_attach_dsi(struct adv7511
*adv
)
182 struct device
*dev
= &adv
->i2c_main
->dev
;
183 struct mipi_dsi_host
*host
;
184 struct mipi_dsi_device
*dsi
;
186 const struct mipi_dsi_device_info info
= { .type
= "adv7533",
191 host
= of_find_mipi_dsi_host_by_node(adv
->host_node
);
193 dev_err(dev
, "failed to find dsi host\n");
194 return -EPROBE_DEFER
;
197 dsi
= mipi_dsi_device_register_full(host
, &info
);
199 dev_err(dev
, "failed to create dsi device\n");
206 dsi
->lanes
= adv
->num_dsi_lanes
;
207 dsi
->format
= MIPI_DSI_FMT_RGB888
;
208 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_SYNC_PULSE
|
209 MIPI_DSI_MODE_EOT_PACKET
| MIPI_DSI_MODE_VIDEO_HSE
;
211 ret
= mipi_dsi_attach(dsi
);
213 dev_err(dev
, "failed to attach dsi to host\n");
220 mipi_dsi_device_unregister(dsi
);
225 void adv7533_detach_dsi(struct adv7511
*adv
)
227 mipi_dsi_detach(adv
->dsi
);
228 mipi_dsi_device_unregister(adv
->dsi
);
231 int adv7533_parse_dt(struct device_node
*np
, struct adv7511
*adv
)
234 struct device_node
*endpoint
;
236 of_property_read_u32(np
, "adi,dsi-lanes", &num_lanes
);
238 if (num_lanes
< 1 || num_lanes
> 4)
241 adv
->num_dsi_lanes
= num_lanes
;
243 endpoint
= of_graph_get_next_endpoint(np
, NULL
);
247 adv
->host_node
= of_graph_get_remote_port_parent(endpoint
);
248 if (!adv
->host_node
) {
249 of_node_put(endpoint
);
253 of_node_put(endpoint
);
254 of_node_put(adv
->host_node
);
256 adv
->use_timing_gen
= !of_property_read_bool(np
,
257 "adi,disable-timing-generator");
259 /* TODO: Check if these need to be parsed by DT or not */
261 adv
->embedded_sync
= false;