2 * Copyright (C) 2009 Francisco Jerez.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <linux/module.h>
29 #include "ch7006_priv.h"
31 /* DRM encoder functions */
33 static void ch7006_encoder_set_config(struct drm_encoder
*encoder
,
36 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
38 priv
->params
= *(struct ch7006_encoder_params
*)params
;
41 static void ch7006_encoder_destroy(struct drm_encoder
*encoder
)
43 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
45 drm_property_destroy(encoder
->dev
, priv
->scale_property
);
48 to_encoder_slave(encoder
)->slave_priv
= NULL
;
50 drm_i2c_encoder_destroy(encoder
);
53 static void ch7006_encoder_dpms(struct drm_encoder
*encoder
, int mode
)
55 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
56 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
57 struct ch7006_state
*state
= &priv
->state
;
59 ch7006_dbg(client
, "\n");
61 if (mode
== priv
->last_dpms
)
63 priv
->last_dpms
= mode
;
65 ch7006_setup_power_state(encoder
);
67 ch7006_load_reg(client
, state
, CH7006_POWER
);
70 static void ch7006_encoder_save(struct drm_encoder
*encoder
)
72 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
73 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
75 ch7006_dbg(client
, "\n");
77 ch7006_state_save(client
, &priv
->saved_state
);
80 static void ch7006_encoder_restore(struct drm_encoder
*encoder
)
82 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
83 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
85 ch7006_dbg(client
, "\n");
87 ch7006_state_load(client
, &priv
->saved_state
);
90 static bool ch7006_encoder_mode_fixup(struct drm_encoder
*encoder
,
91 const struct drm_display_mode
*mode
,
92 struct drm_display_mode
*adjusted_mode
)
94 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
96 /* The ch7006 is painfully picky with the input timings so no
97 * custom modes for now... */
99 priv
->mode
= ch7006_lookup_mode(encoder
, mode
);
104 static int ch7006_encoder_mode_valid(struct drm_encoder
*encoder
,
105 struct drm_display_mode
*mode
)
107 if (ch7006_lookup_mode(encoder
, mode
))
113 static void ch7006_encoder_mode_set(struct drm_encoder
*encoder
,
114 struct drm_display_mode
*drm_mode
,
115 struct drm_display_mode
*adjusted_mode
)
117 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
118 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
119 struct ch7006_encoder_params
*params
= &priv
->params
;
120 struct ch7006_state
*state
= &priv
->state
;
121 uint8_t *regs
= state
->regs
;
122 const struct ch7006_mode
*mode
= priv
->mode
;
123 const struct ch7006_tv_norm_info
*norm
= &ch7006_tv_norms
[priv
->norm
];
126 ch7006_dbg(client
, "\n");
128 regs
[CH7006_DISPMODE
] = norm
->dispmode
| mode
->dispmode
;
129 regs
[CH7006_BWIDTH
] = 0;
130 regs
[CH7006_INPUT_FORMAT
] = bitf(CH7006_INPUT_FORMAT_FORMAT
,
131 params
->input_format
);
133 regs
[CH7006_CLKMODE
] = CH7006_CLKMODE_SUBC_LOCK
134 | bitf(CH7006_CLKMODE_XCM
, params
->xcm
)
135 | bitf(CH7006_CLKMODE_PCM
, params
->pcm
);
136 if (params
->clock_mode
)
137 regs
[CH7006_CLKMODE
] |= CH7006_CLKMODE_MASTER
;
138 if (params
->clock_edge
)
139 regs
[CH7006_CLKMODE
] |= CH7006_CLKMODE_POS_EDGE
;
141 start_active
= (drm_mode
->htotal
& ~0x7) - (drm_mode
->hsync_start
& ~0x7);
142 regs
[CH7006_POV
] = bitf(CH7006_POV_START_ACTIVE_8
, start_active
);
143 regs
[CH7006_START_ACTIVE
] = bitf(CH7006_START_ACTIVE_0
, start_active
);
145 regs
[CH7006_INPUT_SYNC
] = 0;
146 if (params
->sync_direction
)
147 regs
[CH7006_INPUT_SYNC
] |= CH7006_INPUT_SYNC_OUTPUT
;
148 if (params
->sync_encoding
)
149 regs
[CH7006_INPUT_SYNC
] |= CH7006_INPUT_SYNC_EMBEDDED
;
150 if (drm_mode
->flags
& DRM_MODE_FLAG_PVSYNC
)
151 regs
[CH7006_INPUT_SYNC
] |= CH7006_INPUT_SYNC_PVSYNC
;
152 if (drm_mode
->flags
& DRM_MODE_FLAG_PHSYNC
)
153 regs
[CH7006_INPUT_SYNC
] |= CH7006_INPUT_SYNC_PHSYNC
;
155 regs
[CH7006_DETECT
] = 0;
156 regs
[CH7006_BCLKOUT
] = 0;
158 regs
[CH7006_SUBC_INC3
] = 0;
159 if (params
->pout_level
)
160 regs
[CH7006_SUBC_INC3
] |= CH7006_SUBC_INC3_POUT_3_3V
;
162 regs
[CH7006_SUBC_INC4
] = 0;
163 if (params
->active_detect
)
164 regs
[CH7006_SUBC_INC4
] |= CH7006_SUBC_INC4_DS_INPUT
;
166 regs
[CH7006_PLL_CONTROL
] = priv
->saved_state
.regs
[CH7006_PLL_CONTROL
];
168 ch7006_setup_levels(encoder
);
169 ch7006_setup_subcarrier(encoder
);
170 ch7006_setup_pll(encoder
);
171 ch7006_setup_power_state(encoder
);
172 ch7006_setup_properties(encoder
);
174 ch7006_state_load(client
, state
);
177 static enum drm_connector_status
ch7006_encoder_detect(struct drm_encoder
*encoder
,
178 struct drm_connector
*connector
)
180 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
181 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
182 struct ch7006_state
*state
= &priv
->state
;
185 ch7006_dbg(client
, "\n");
187 ch7006_save_reg(client
, state
, CH7006_DETECT
);
188 ch7006_save_reg(client
, state
, CH7006_POWER
);
189 ch7006_save_reg(client
, state
, CH7006_CLKMODE
);
191 ch7006_write(client
, CH7006_POWER
, CH7006_POWER_RESET
|
192 bitfs(CH7006_POWER_LEVEL
, NORMAL
));
193 ch7006_write(client
, CH7006_CLKMODE
, CH7006_CLKMODE_MASTER
);
195 ch7006_write(client
, CH7006_DETECT
, CH7006_DETECT_SENSE
);
197 ch7006_write(client
, CH7006_DETECT
, 0);
199 det
= ch7006_read(client
, CH7006_DETECT
);
201 ch7006_load_reg(client
, state
, CH7006_CLKMODE
);
202 ch7006_load_reg(client
, state
, CH7006_POWER
);
203 ch7006_load_reg(client
, state
, CH7006_DETECT
);
205 if ((det
& (CH7006_DETECT_SVIDEO_Y_TEST
|
206 CH7006_DETECT_SVIDEO_C_TEST
|
207 CH7006_DETECT_CVBS_TEST
)) == 0)
208 priv
->subconnector
= DRM_MODE_SUBCONNECTOR_SCART
;
209 else if ((det
& (CH7006_DETECT_SVIDEO_Y_TEST
|
210 CH7006_DETECT_SVIDEO_C_TEST
)) == 0)
211 priv
->subconnector
= DRM_MODE_SUBCONNECTOR_SVIDEO
;
212 else if ((det
& CH7006_DETECT_CVBS_TEST
) == 0)
213 priv
->subconnector
= DRM_MODE_SUBCONNECTOR_Composite
;
215 priv
->subconnector
= DRM_MODE_SUBCONNECTOR_Unknown
;
217 drm_object_property_set_value(&connector
->base
,
218 encoder
->dev
->mode_config
.tv_subconnector_property
,
221 return priv
->subconnector
? connector_status_connected
:
222 connector_status_disconnected
;
225 static int ch7006_encoder_get_modes(struct drm_encoder
*encoder
,
226 struct drm_connector
*connector
)
228 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
229 const struct ch7006_mode
*mode
;
232 for (mode
= ch7006_modes
; mode
->mode
.clock
; mode
++) {
233 if (~mode
->valid_scales
& 1<<priv
->scale
||
234 ~mode
->valid_norms
& 1<<priv
->norm
)
237 drm_mode_probed_add(connector
,
238 drm_mode_duplicate(encoder
->dev
, &mode
->mode
));
246 static int ch7006_encoder_create_resources(struct drm_encoder
*encoder
,
247 struct drm_connector
*connector
)
249 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
250 struct drm_device
*dev
= encoder
->dev
;
251 struct drm_mode_config
*conf
= &dev
->mode_config
;
253 drm_mode_create_tv_properties(dev
, NUM_TV_NORMS
, ch7006_tv_norm_names
);
255 priv
->scale_property
= drm_property_create_range(dev
, 0, "scale", 0, 2);
256 if (!priv
->scale_property
)
259 drm_object_attach_property(&connector
->base
, conf
->tv_select_subconnector_property
,
260 priv
->select_subconnector
);
261 drm_object_attach_property(&connector
->base
, conf
->tv_subconnector_property
,
263 drm_object_attach_property(&connector
->base
, conf
->tv_left_margin_property
,
265 drm_object_attach_property(&connector
->base
, conf
->tv_bottom_margin_property
,
267 drm_object_attach_property(&connector
->base
, conf
->tv_mode_property
,
269 drm_object_attach_property(&connector
->base
, conf
->tv_brightness_property
,
271 drm_object_attach_property(&connector
->base
, conf
->tv_contrast_property
,
273 drm_object_attach_property(&connector
->base
, conf
->tv_flicker_reduction_property
,
275 drm_object_attach_property(&connector
->base
, priv
->scale_property
,
281 static int ch7006_encoder_set_property(struct drm_encoder
*encoder
,
282 struct drm_connector
*connector
,
283 struct drm_property
*property
,
286 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
287 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
288 struct ch7006_state
*state
= &priv
->state
;
289 struct drm_mode_config
*conf
= &encoder
->dev
->mode_config
;
290 struct drm_crtc
*crtc
= encoder
->crtc
;
291 bool modes_changed
= false;
293 ch7006_dbg(client
, "\n");
295 if (property
== conf
->tv_select_subconnector_property
) {
296 priv
->select_subconnector
= val
;
298 ch7006_setup_power_state(encoder
);
300 ch7006_load_reg(client
, state
, CH7006_POWER
);
302 } else if (property
== conf
->tv_left_margin_property
) {
305 ch7006_setup_properties(encoder
);
307 ch7006_load_reg(client
, state
, CH7006_POV
);
308 ch7006_load_reg(client
, state
, CH7006_HPOS
);
310 } else if (property
== conf
->tv_bottom_margin_property
) {
313 ch7006_setup_properties(encoder
);
315 ch7006_load_reg(client
, state
, CH7006_POV
);
316 ch7006_load_reg(client
, state
, CH7006_VPOS
);
318 } else if (property
== conf
->tv_mode_property
) {
319 if (connector
->dpms
!= DRM_MODE_DPMS_OFF
)
324 modes_changed
= true;
326 } else if (property
== conf
->tv_brightness_property
) {
327 priv
->brightness
= val
;
329 ch7006_setup_levels(encoder
);
331 ch7006_load_reg(client
, state
, CH7006_BLACK_LEVEL
);
333 } else if (property
== conf
->tv_contrast_property
) {
334 priv
->contrast
= val
;
336 ch7006_setup_properties(encoder
);
338 ch7006_load_reg(client
, state
, CH7006_CONTRAST
);
340 } else if (property
== conf
->tv_flicker_reduction_property
) {
343 ch7006_setup_properties(encoder
);
345 ch7006_load_reg(client
, state
, CH7006_FFILTER
);
347 } else if (property
== priv
->scale_property
) {
348 if (connector
->dpms
!= DRM_MODE_DPMS_OFF
)
353 modes_changed
= true;
360 drm_helper_probe_single_connector_modes(connector
, 0, 0);
363 drm_crtc_helper_set_mode(crtc
, &crtc
->mode
,
371 static const struct drm_encoder_slave_funcs ch7006_encoder_funcs
= {
372 .set_config
= ch7006_encoder_set_config
,
373 .destroy
= ch7006_encoder_destroy
,
374 .dpms
= ch7006_encoder_dpms
,
375 .save
= ch7006_encoder_save
,
376 .restore
= ch7006_encoder_restore
,
377 .mode_fixup
= ch7006_encoder_mode_fixup
,
378 .mode_valid
= ch7006_encoder_mode_valid
,
379 .mode_set
= ch7006_encoder_mode_set
,
380 .detect
= ch7006_encoder_detect
,
381 .get_modes
= ch7006_encoder_get_modes
,
382 .create_resources
= ch7006_encoder_create_resources
,
383 .set_property
= ch7006_encoder_set_property
,
387 /* I2C driver functions */
389 static int ch7006_probe(struct i2c_client
*client
, const struct i2c_device_id
*id
)
391 uint8_t addr
= CH7006_VERSION_ID
;
395 ch7006_dbg(client
, "\n");
397 ret
= i2c_master_send(client
, &addr
, sizeof(addr
));
401 ret
= i2c_master_recv(client
, &val
, sizeof(val
));
405 ch7006_info(client
, "Detected version ID: %x\n", val
);
407 /* I don't know what this is for, but otherwise I get no
410 ch7006_write(client
, 0x3d, 0x0);
415 ch7006_err(client
, "Error %d reading version ID\n", ret
);
420 static int ch7006_remove(struct i2c_client
*client
)
422 ch7006_dbg(client
, "\n");
427 static int ch7006_resume(struct device
*dev
)
429 struct i2c_client
*client
= to_i2c_client(dev
);
431 ch7006_dbg(client
, "\n");
433 ch7006_write(client
, 0x3d, 0x0);
438 static int ch7006_encoder_init(struct i2c_client
*client
,
439 struct drm_device
*dev
,
440 struct drm_encoder_slave
*encoder
)
442 struct ch7006_priv
*priv
;
445 ch7006_dbg(client
, "\n");
447 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
451 encoder
->slave_priv
= priv
;
452 encoder
->slave_funcs
= &ch7006_encoder_funcs
;
454 priv
->norm
= TV_NORM_PAL
;
455 priv
->select_subconnector
= DRM_MODE_SUBCONNECTOR_Automatic
;
456 priv
->subconnector
= DRM_MODE_SUBCONNECTOR_Unknown
;
459 priv
->brightness
= 50;
463 priv
->last_dpms
= -1;
464 priv
->chip_version
= ch7006_read(client
, CH7006_VERSION_ID
);
466 if (ch7006_tv_norm
) {
467 for (i
= 0; i
< NUM_TV_NORMS
; i
++) {
468 if (!strcmp(ch7006_tv_norm_names
[i
], ch7006_tv_norm
)) {
474 if (i
== NUM_TV_NORMS
)
475 ch7006_err(client
, "Invalid TV norm setting \"%s\".\n",
479 if (ch7006_scale
>= 0 && ch7006_scale
<= 2)
480 priv
->scale
= ch7006_scale
;
482 ch7006_err(client
, "Invalid scale setting \"%d\".\n",
488 static const struct i2c_device_id ch7006_ids
[] = {
492 MODULE_DEVICE_TABLE(i2c
, ch7006_ids
);
494 static const struct dev_pm_ops ch7006_pm_ops
= {
495 .resume
= ch7006_resume
,
498 static struct drm_i2c_encoder_driver ch7006_driver
= {
500 .probe
= ch7006_probe
,
501 .remove
= ch7006_remove
,
505 .pm
= &ch7006_pm_ops
,
508 .id_table
= ch7006_ids
,
511 .encoder_init
= ch7006_encoder_init
,
515 /* Module initialization */
517 static int __init
ch7006_init(void)
519 return drm_i2c_encoder_register(THIS_MODULE
, &ch7006_driver
);
522 static void __exit
ch7006_exit(void)
524 drm_i2c_encoder_unregister(&ch7006_driver
);
528 module_param_named(debug
, ch7006_debug
, int, 0600);
529 MODULE_PARM_DESC(debug
, "Enable debug output.");
531 char *ch7006_tv_norm
;
532 module_param_named(tv_norm
, ch7006_tv_norm
, charp
, 0600);
533 MODULE_PARM_DESC(tv_norm
, "Default TV norm.\n"
534 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n"
537 int ch7006_scale
= 1;
538 module_param_named(scale
, ch7006_scale
, int, 0600);
539 MODULE_PARM_DESC(scale
, "Default scale.\n"
540 "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n"
541 "\t\t\t1 -> Select default video modes.\n"
542 "\t\t\t2 -> Select video modes with a lower blanking ratio.");
544 MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
545 MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver");
546 MODULE_LICENSE("GPL and additional rights");
548 module_init(ch7006_init
);
549 module_exit(ch7006_exit
);