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 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 struct ch7006_mode
*mode
= priv
->mode
;
123 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_connector_property_set_value(connector
,
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 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(dev
, DRM_MODE_PROP_RANGE
,
257 priv
->scale_property
->values
[0] = 0;
258 priv
->scale_property
->values
[1] = 2;
260 drm_connector_attach_property(connector
, conf
->tv_select_subconnector_property
,
261 priv
->select_subconnector
);
262 drm_connector_attach_property(connector
, conf
->tv_subconnector_property
,
264 drm_connector_attach_property(connector
, conf
->tv_left_margin_property
,
266 drm_connector_attach_property(connector
, conf
->tv_bottom_margin_property
,
268 drm_connector_attach_property(connector
, conf
->tv_mode_property
,
270 drm_connector_attach_property(connector
, conf
->tv_brightness_property
,
272 drm_connector_attach_property(connector
, conf
->tv_contrast_property
,
274 drm_connector_attach_property(connector
, conf
->tv_flicker_reduction_property
,
276 drm_connector_attach_property(connector
, priv
->scale_property
,
282 static int ch7006_encoder_set_property(struct drm_encoder
*encoder
,
283 struct drm_connector
*connector
,
284 struct drm_property
*property
,
287 struct i2c_client
*client
= drm_i2c_encoder_get_client(encoder
);
288 struct ch7006_priv
*priv
= to_ch7006_priv(encoder
);
289 struct ch7006_state
*state
= &priv
->state
;
290 struct drm_mode_config
*conf
= &encoder
->dev
->mode_config
;
291 struct drm_crtc
*crtc
= encoder
->crtc
;
292 bool modes_changed
= false;
294 ch7006_dbg(client
, "\n");
296 if (property
== conf
->tv_select_subconnector_property
) {
297 priv
->select_subconnector
= val
;
299 ch7006_setup_power_state(encoder
);
301 ch7006_load_reg(client
, state
, CH7006_POWER
);
303 } else if (property
== conf
->tv_left_margin_property
) {
306 ch7006_setup_properties(encoder
);
308 ch7006_load_reg(client
, state
, CH7006_POV
);
309 ch7006_load_reg(client
, state
, CH7006_HPOS
);
311 } else if (property
== conf
->tv_bottom_margin_property
) {
314 ch7006_setup_properties(encoder
);
316 ch7006_load_reg(client
, state
, CH7006_POV
);
317 ch7006_load_reg(client
, state
, CH7006_VPOS
);
319 } else if (property
== conf
->tv_mode_property
) {
320 if (connector
->dpms
!= DRM_MODE_DPMS_OFF
)
325 modes_changed
= true;
327 } else if (property
== conf
->tv_brightness_property
) {
328 priv
->brightness
= val
;
330 ch7006_setup_levels(encoder
);
332 ch7006_load_reg(client
, state
, CH7006_BLACK_LEVEL
);
334 } else if (property
== conf
->tv_contrast_property
) {
335 priv
->contrast
= val
;
337 ch7006_setup_properties(encoder
);
339 ch7006_load_reg(client
, state
, CH7006_CONTRAST
);
341 } else if (property
== conf
->tv_flicker_reduction_property
) {
344 ch7006_setup_properties(encoder
);
346 ch7006_load_reg(client
, state
, CH7006_FFILTER
);
348 } else if (property
== priv
->scale_property
) {
349 if (connector
->dpms
!= DRM_MODE_DPMS_OFF
)
354 modes_changed
= true;
361 drm_helper_probe_single_connector_modes(connector
, 0, 0);
363 /* Disable the crtc to ensure a full modeset is
364 * performed whenever it's turned on again. */
366 struct drm_mode_set modeset
= {
370 crtc
->funcs
->set_config(&modeset
);
377 static struct drm_encoder_slave_funcs ch7006_encoder_funcs
= {
378 .set_config
= ch7006_encoder_set_config
,
379 .destroy
= ch7006_encoder_destroy
,
380 .dpms
= ch7006_encoder_dpms
,
381 .save
= ch7006_encoder_save
,
382 .restore
= ch7006_encoder_restore
,
383 .mode_fixup
= ch7006_encoder_mode_fixup
,
384 .mode_valid
= ch7006_encoder_mode_valid
,
385 .mode_set
= ch7006_encoder_mode_set
,
386 .detect
= ch7006_encoder_detect
,
387 .get_modes
= ch7006_encoder_get_modes
,
388 .create_resources
= ch7006_encoder_create_resources
,
389 .set_property
= ch7006_encoder_set_property
,
393 /* I2C driver functions */
395 static int ch7006_probe(struct i2c_client
*client
, const struct i2c_device_id
*id
)
397 uint8_t addr
= CH7006_VERSION_ID
;
401 ch7006_dbg(client
, "\n");
403 ret
= i2c_master_send(client
, &addr
, sizeof(addr
));
407 ret
= i2c_master_recv(client
, &val
, sizeof(val
));
411 ch7006_info(client
, "Detected version ID: %x\n", val
);
413 /* I don't know what this is for, but otherwise I get no
416 ch7006_write(client
, 0x3d, 0x0);
421 ch7006_err(client
, "Error %d reading version ID\n", ret
);
426 static int ch7006_remove(struct i2c_client
*client
)
428 ch7006_dbg(client
, "\n");
433 static int ch7006_suspend(struct i2c_client
*client
, pm_message_t mesg
)
435 ch7006_dbg(client
, "\n");
440 static int ch7006_resume(struct i2c_client
*client
)
442 ch7006_dbg(client
, "\n");
444 ch7006_write(client
, 0x3d, 0x0);
449 static int ch7006_encoder_init(struct i2c_client
*client
,
450 struct drm_device
*dev
,
451 struct drm_encoder_slave
*encoder
)
453 struct ch7006_priv
*priv
;
456 ch7006_dbg(client
, "\n");
458 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
462 encoder
->slave_priv
= priv
;
463 encoder
->slave_funcs
= &ch7006_encoder_funcs
;
465 priv
->norm
= TV_NORM_PAL
;
466 priv
->select_subconnector
= DRM_MODE_SUBCONNECTOR_Automatic
;
467 priv
->subconnector
= DRM_MODE_SUBCONNECTOR_Unknown
;
470 priv
->brightness
= 50;
474 priv
->last_dpms
= -1;
475 priv
->chip_version
= ch7006_read(client
, CH7006_VERSION_ID
);
477 if (ch7006_tv_norm
) {
478 for (i
= 0; i
< NUM_TV_NORMS
; i
++) {
479 if (!strcmp(ch7006_tv_norm_names
[i
], ch7006_tv_norm
)) {
485 if (i
== NUM_TV_NORMS
)
486 ch7006_err(client
, "Invalid TV norm setting \"%s\".\n",
490 if (ch7006_scale
>= 0 && ch7006_scale
<= 2)
491 priv
->scale
= ch7006_scale
;
493 ch7006_err(client
, "Invalid scale setting \"%d\".\n",
499 static struct i2c_device_id ch7006_ids
[] = {
503 MODULE_DEVICE_TABLE(i2c
, ch7006_ids
);
505 static struct drm_i2c_encoder_driver ch7006_driver
= {
507 .probe
= ch7006_probe
,
508 .remove
= ch7006_remove
,
509 .suspend
= ch7006_suspend
,
510 .resume
= ch7006_resume
,
516 .id_table
= ch7006_ids
,
519 .encoder_init
= ch7006_encoder_init
,
523 /* Module initialization */
525 static int __init
ch7006_init(void)
527 return drm_i2c_encoder_register(THIS_MODULE
, &ch7006_driver
);
530 static void __exit
ch7006_exit(void)
532 drm_i2c_encoder_unregister(&ch7006_driver
);
536 module_param_named(debug
, ch7006_debug
, int, 0600);
537 MODULE_PARM_DESC(debug
, "Enable debug output.");
539 char *ch7006_tv_norm
;
540 module_param_named(tv_norm
, ch7006_tv_norm
, charp
, 0600);
541 MODULE_PARM_DESC(tv_norm
, "Default TV norm.\n"
542 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n"
545 int ch7006_scale
= 1;
546 module_param_named(scale
, ch7006_scale
, int, 0600);
547 MODULE_PARM_DESC(scale
, "Default scale.\n"
548 "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n"
549 "\t\t\t1 -> Select default video modes.\n"
550 "\t\t\t2 -> Select video modes with a lower blanking ratio.");
552 MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
553 MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver");
554 MODULE_LICENSE("GPL and additional rights");
556 module_init(ch7006_init
);
557 module_exit(ch7006_exit
);