1 /* 2 * Copyright (C) 2009 Francisco Jerez. 3 * All Rights Reserved. 4 * 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: 12 * 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. 16 * 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. 24 * 25 */ 26 27 #include <linux/module.h> 28 29 #include <drm/drm_crtc_helper.h> 30 31 #include "ch7006_priv.h" 32 33 /* DRM encoder functions */ 34 35 static void ch7006_encoder_set_config(struct drm_encoder *encoder, 36 void *params) 37 { 38 struct ch7006_priv *priv = to_ch7006_priv(encoder); 39 40 priv->params = *(struct ch7006_encoder_params *)params; 41 } 42 43 static void ch7006_encoder_destroy(struct drm_encoder *encoder) 44 { 45 struct ch7006_priv *priv = to_ch7006_priv(encoder); 46 47 drm_property_destroy(encoder->dev, priv->scale_property); 48 49 kfree(priv); 50 to_encoder_slave(encoder)->slave_priv = NULL; 51 52 drm_i2c_encoder_destroy(encoder); 53 } 54 55 static void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode) 56 { 57 struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 58 struct ch7006_priv *priv = to_ch7006_priv(encoder); 59 struct ch7006_state *state = &priv->state; 60 61 ch7006_dbg(client, "\n"); 62 63 if (mode == priv->last_dpms) 64 return; 65 priv->last_dpms = mode; 66 67 ch7006_setup_power_state(encoder); 68 69 ch7006_load_reg(client, state, CH7006_POWER); 70 } 71 72 static void ch7006_encoder_save(struct drm_encoder *encoder) 73 { 74 struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 75 struct ch7006_priv *priv = to_ch7006_priv(encoder); 76 77 ch7006_dbg(client, "\n"); 78 79 ch7006_state_save(client, &priv->saved_state); 80 } 81 82 static void ch7006_encoder_restore(struct drm_encoder *encoder) 83 { 84 struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 85 struct ch7006_priv *priv = to_ch7006_priv(encoder); 86 87 ch7006_dbg(client, "\n"); 88 89 ch7006_state_load(client, &priv->saved_state); 90 } 91 92 static bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder, 93 const struct drm_display_mode *mode, 94 struct drm_display_mode *adjusted_mode) 95 { 96 struct ch7006_priv *priv = to_ch7006_priv(encoder); 97 98 /* The ch7006 is painfully picky with the input timings so no 99 * custom modes for now... */ 100 101 priv->mode = ch7006_lookup_mode(encoder, mode); 102 103 return !!priv->mode; 104 } 105 106 static int ch7006_encoder_mode_valid(struct drm_encoder *encoder, 107 struct drm_display_mode *mode) 108 { 109 if (ch7006_lookup_mode(encoder, mode)) 110 return MODE_OK; 111 else 112 return MODE_BAD; 113 } 114 115 static void ch7006_encoder_mode_set(struct drm_encoder *encoder, 116 struct drm_display_mode *drm_mode, 117 struct drm_display_mode *adjusted_mode) 118 { 119 struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 120 struct ch7006_priv *priv = to_ch7006_priv(encoder); 121 struct ch7006_encoder_params *params = &priv->params; 122 struct ch7006_state *state = &priv->state; 123 uint8_t *regs = state->regs; 124 const struct ch7006_mode *mode = priv->mode; 125 const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; 126 int start_active; 127 128 ch7006_dbg(client, "\n"); 129 130 regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode; 131 regs[CH7006_BWIDTH] = 0; 132 regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT, 133 params->input_format); 134 135 regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK 136 | bitf(CH7006_CLKMODE_XCM, params->xcm) 137 | bitf(CH7006_CLKMODE_PCM, params->pcm); 138 if (params->clock_mode) 139 regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER; 140 if (params->clock_edge) 141 regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE; 142 143 start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7); 144 regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active); 145 regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active); 146 147 regs[CH7006_INPUT_SYNC] = 0; 148 if (params->sync_direction) 149 regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT; 150 if (params->sync_encoding) 151 regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED; 152 if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC) 153 regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC; 154 if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC) 155 regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC; 156 157 regs[CH7006_DETECT] = 0; 158 regs[CH7006_BCLKOUT] = 0; 159 160 regs[CH7006_SUBC_INC3] = 0; 161 if (params->pout_level) 162 regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V; 163 164 regs[CH7006_SUBC_INC4] = 0; 165 if (params->active_detect) 166 regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT; 167 168 regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL]; 169 170 ch7006_setup_levels(encoder); 171 ch7006_setup_subcarrier(encoder); 172 ch7006_setup_pll(encoder); 173 ch7006_setup_power_state(encoder); 174 ch7006_setup_properties(encoder); 175 176 ch7006_state_load(client, state); 177 } 178 179 static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder, 180 struct drm_connector *connector) 181 { 182 struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 183 struct ch7006_priv *priv = to_ch7006_priv(encoder); 184 struct ch7006_state *state = &priv->state; 185 int det; 186 187 ch7006_dbg(client, "\n"); 188 189 ch7006_save_reg(client, state, CH7006_DETECT); 190 ch7006_save_reg(client, state, CH7006_POWER); 191 ch7006_save_reg(client, state, CH7006_CLKMODE); 192 193 ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET | 194 bitfs(CH7006_POWER_LEVEL, NORMAL)); 195 ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER); 196 197 ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE); 198 199 ch7006_write(client, CH7006_DETECT, 0); 200 201 det = ch7006_read(client, CH7006_DETECT); 202 203 ch7006_load_reg(client, state, CH7006_CLKMODE); 204 ch7006_load_reg(client, state, CH7006_POWER); 205 ch7006_load_reg(client, state, CH7006_DETECT); 206 207 if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| 208 CH7006_DETECT_SVIDEO_C_TEST| 209 CH7006_DETECT_CVBS_TEST)) == 0) 210 priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART; 211 else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| 212 CH7006_DETECT_SVIDEO_C_TEST)) == 0) 213 priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO; 214 else if ((det & CH7006_DETECT_CVBS_TEST) == 0) 215 priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite; 216 else 217 priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; 218 219 drm_object_property_set_value(&connector->base, 220 encoder->dev->mode_config.tv_subconnector_property, 221 priv->subconnector); 222 223 return priv->subconnector ? connector_status_connected : 224 connector_status_disconnected; 225 } 226 227 static int ch7006_encoder_get_modes(struct drm_encoder *encoder, 228 struct drm_connector *connector) 229 { 230 struct ch7006_priv *priv = to_ch7006_priv(encoder); 231 const struct ch7006_mode *mode; 232 int n = 0; 233 234 for (mode = ch7006_modes; mode->mode.clock; mode++) { 235 if (~mode->valid_scales & 1<<priv->scale || 236 ~mode->valid_norms & 1<<priv->norm) 237 continue; 238 239 drm_mode_probed_add(connector, 240 drm_mode_duplicate(encoder->dev, &mode->mode)); 241 242 n++; 243 } 244 245 return n; 246 } 247 248 static int ch7006_encoder_create_resources(struct drm_encoder *encoder, 249 struct drm_connector *connector) 250 { 251 struct ch7006_priv *priv = to_ch7006_priv(encoder); 252 struct drm_device *dev = encoder->dev; 253 struct drm_mode_config *conf = &dev->mode_config; 254 255 drm_mode_create_tv_properties_legacy(dev, NUM_TV_NORMS, ch7006_tv_norm_names); 256 257 priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2); 258 if (!priv->scale_property) 259 return -ENOMEM; 260 261 drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property, 262 priv->select_subconnector); 263 drm_object_attach_property(&connector->base, conf->tv_subconnector_property, 264 priv->subconnector); 265 drm_object_attach_property(&connector->base, conf->tv_left_margin_property, 266 priv->hmargin); 267 drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property, 268 priv->vmargin); 269 drm_object_attach_property(&connector->base, conf->legacy_tv_mode_property, 270 priv->norm); 271 drm_object_attach_property(&connector->base, conf->tv_brightness_property, 272 priv->brightness); 273 drm_object_attach_property(&connector->base, conf->tv_contrast_property, 274 priv->contrast); 275 drm_object_attach_property(&connector->base, conf->tv_flicker_reduction_property, 276 priv->flicker); 277 drm_object_attach_property(&connector->base, priv->scale_property, 278 priv->scale); 279 280 return 0; 281 } 282 283 static int ch7006_encoder_set_property(struct drm_encoder *encoder, 284 struct drm_connector *connector, 285 struct drm_property *property, 286 uint64_t val) 287 { 288 struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 289 struct ch7006_priv *priv = to_ch7006_priv(encoder); 290 struct ch7006_state *state = &priv->state; 291 struct drm_mode_config *conf = &encoder->dev->mode_config; 292 struct drm_crtc *crtc = encoder->crtc; 293 bool modes_changed = false; 294 295 ch7006_dbg(client, "\n"); 296 297 if (property == conf->tv_select_subconnector_property) { 298 priv->select_subconnector = val; 299 300 ch7006_setup_power_state(encoder); 301 302 ch7006_load_reg(client, state, CH7006_POWER); 303 304 } else if (property == conf->tv_left_margin_property) { 305 priv->hmargin = val; 306 307 ch7006_setup_properties(encoder); 308 309 ch7006_load_reg(client, state, CH7006_POV); 310 ch7006_load_reg(client, state, CH7006_HPOS); 311 312 } else if (property == conf->tv_bottom_margin_property) { 313 priv->vmargin = val; 314 315 ch7006_setup_properties(encoder); 316 317 ch7006_load_reg(client, state, CH7006_POV); 318 ch7006_load_reg(client, state, CH7006_VPOS); 319 320 } else if (property == conf->legacy_tv_mode_property) { 321 if (connector->dpms != DRM_MODE_DPMS_OFF) 322 return -EINVAL; 323 324 priv->norm = val; 325 326 modes_changed = true; 327 328 } else if (property == conf->tv_brightness_property) { 329 priv->brightness = val; 330 331 ch7006_setup_levels(encoder); 332 333 ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); 334 335 } else if (property == conf->tv_contrast_property) { 336 priv->contrast = val; 337 338 ch7006_setup_properties(encoder); 339 340 ch7006_load_reg(client, state, CH7006_CONTRAST); 341 342 } else if (property == conf->tv_flicker_reduction_property) { 343 priv->flicker = val; 344 345 ch7006_setup_properties(encoder); 346 347 ch7006_load_reg(client, state, CH7006_FFILTER); 348 349 } else if (property == priv->scale_property) { 350 if (connector->dpms != DRM_MODE_DPMS_OFF) 351 return -EINVAL; 352 353 priv->scale = val; 354 355 modes_changed = true; 356 357 } else { 358 return -EINVAL; 359 } 360 361 if (modes_changed) { 362 drm_helper_probe_single_connector_modes(connector, 0, 0); 363 364 if (crtc) 365 drm_crtc_helper_set_mode(crtc, &crtc->mode, 366 crtc->x, crtc->y, 367 crtc->primary->fb); 368 } 369 370 return 0; 371 } 372 373 static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = { 374 .set_config = ch7006_encoder_set_config, 375 .destroy = ch7006_encoder_destroy, 376 .dpms = ch7006_encoder_dpms, 377 .save = ch7006_encoder_save, 378 .restore = ch7006_encoder_restore, 379 .mode_fixup = ch7006_encoder_mode_fixup, 380 .mode_valid = ch7006_encoder_mode_valid, 381 .mode_set = ch7006_encoder_mode_set, 382 .detect = ch7006_encoder_detect, 383 .get_modes = ch7006_encoder_get_modes, 384 .create_resources = ch7006_encoder_create_resources, 385 .set_property = ch7006_encoder_set_property, 386 }; 387 388 389 /* I2C driver functions */ 390 391 static int ch7006_probe(struct i2c_client *client) 392 { 393 uint8_t addr = CH7006_VERSION_ID; 394 uint8_t val; 395 int ret; 396 397 ch7006_dbg(client, "\n"); 398 399 ret = i2c_master_send(client, &addr, sizeof(addr)); 400 if (ret < 0) 401 goto fail; 402 403 ret = i2c_master_recv(client, &val, sizeof(val)); 404 if (ret < 0) 405 goto fail; 406 407 ch7006_info(client, "Detected version ID: %x\n", val); 408 409 /* I don't know what this is for, but otherwise I get no 410 * signal. 411 */ 412 ch7006_write(client, 0x3d, 0x0); 413 414 return 0; 415 416 fail: 417 ch7006_err(client, "Error %d reading version ID\n", ret); 418 419 return -ENODEV; 420 } 421 422 static void ch7006_remove(struct i2c_client *client) 423 { 424 ch7006_dbg(client, "\n"); 425 } 426 427 static int ch7006_resume(struct device *dev) 428 { 429 struct i2c_client *client = to_i2c_client(dev); 430 431 ch7006_dbg(client, "\n"); 432 433 ch7006_write(client, 0x3d, 0x0); 434 435 return 0; 436 } 437 438 static int ch7006_encoder_init(struct i2c_client *client, 439 struct drm_device *dev, 440 struct drm_encoder_slave *encoder) 441 { 442 struct ch7006_priv *priv; 443 int i; 444 445 ch7006_dbg(client, "\n"); 446 447 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 448 if (!priv) 449 return -ENOMEM; 450 451 encoder->slave_priv = priv; 452 encoder->slave_funcs = &ch7006_encoder_funcs; 453 454 priv->norm = TV_NORM_PAL; 455 priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic; 456 priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; 457 priv->scale = 1; 458 priv->contrast = 50; 459 priv->brightness = 50; 460 priv->flicker = 50; 461 priv->hmargin = 50; 462 priv->vmargin = 50; 463 priv->last_dpms = -1; 464 priv->chip_version = ch7006_read(client, CH7006_VERSION_ID); 465 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)) { 469 priv->norm = i; 470 break; 471 } 472 } 473 474 if (i == NUM_TV_NORMS) 475 ch7006_err(client, "Invalid TV norm setting \"%s\".\n", 476 ch7006_tv_norm); 477 } 478 479 if (ch7006_scale >= 0 && ch7006_scale <= 2) 480 priv->scale = ch7006_scale; 481 else 482 ch7006_err(client, "Invalid scale setting \"%d\".\n", 483 ch7006_scale); 484 485 return 0; 486 } 487 488 static const struct i2c_device_id ch7006_ids[] = { 489 { "ch7006", 0 }, 490 { } 491 }; 492 MODULE_DEVICE_TABLE(i2c, ch7006_ids); 493 494 static const struct dev_pm_ops ch7006_pm_ops = { 495 .resume = ch7006_resume, 496 }; 497 498 static struct drm_i2c_encoder_driver ch7006_driver = { 499 .i2c_driver = { 500 .probe = ch7006_probe, 501 .remove = ch7006_remove, 502 503 .driver = { 504 .name = "ch7006", 505 .pm = &ch7006_pm_ops, 506 }, 507 508 .id_table = ch7006_ids, 509 }, 510 511 .encoder_init = ch7006_encoder_init, 512 }; 513 514 515 /* Module initialization */ 516 517 static int __init ch7006_init(void) 518 { 519 return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver); 520 } 521 522 static void __exit ch7006_exit(void) 523 { 524 drm_i2c_encoder_unregister(&ch7006_driver); 525 } 526 527 int ch7006_debug; 528 module_param_named(debug, ch7006_debug, int, 0600); 529 MODULE_PARM_DESC(debug, "Enable debug output."); 530 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" 535 "\t\tDefault: PAL"); 536 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."); 543 544 MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>"); 545 MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver"); 546 MODULE_LICENSE("GPL and additional rights"); 547 548 module_init(ch7006_init); 549 module_exit(ch7006_exit); 550