16ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/* 26ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Copyright (C) 2009 Francisco Jerez. 36ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * All Rights Reserved. 46ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * 56ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining 66ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * a copy of this software and associated documentation files (the 76ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * "Software"), to deal in the Software without restriction, including 86ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * without limitation the rights to use, copy, modify, merge, publish, 96ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * distribute, sublicense, and/or sell copies of the Software, and to 106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * permit persons to whom the Software is furnished to do so, subject to 116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * the following conditions: 126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * 136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * The above copyright notice and this permission notice (including the 146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * next paragraph) shall be included in all copies or substantial 156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * portions of the Software. 166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * 176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * 256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs */ 266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 27e0cd3608135b2ed8eddbe3fdf048d22e0593d836Paul Gortmaker#include <linux/module.h> 28e0cd3608135b2ed8eddbe3fdf048d22e0593d836Paul Gortmaker 296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "ch7006_priv.h" 306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/* DRM encoder functions */ 326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void ch7006_encoder_set_config(struct drm_encoder *encoder, 346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs void *params) 356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 386d6a413aa23c8bc7a5787596e06f3d6d8d4f11c7Francisco Jerez priv->params = *(struct ch7006_encoder_params *)params; 396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void ch7006_encoder_destroy(struct drm_encoder *encoder) 426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_property_destroy(encoder->dev, priv->scale_property); 466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs kfree(priv); 486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs to_encoder_slave(encoder)->slave_priv = NULL; 496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_i2c_encoder_destroy(encoder); 516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode) 546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_state *state = &priv->state; 586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (mode == priv->last_dpms) 626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return; 636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->last_dpms = mode; 646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_power_state(encoder); 666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_POWER); 686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void ch7006_encoder_save(struct drm_encoder *encoder) 716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_state_save(client, &priv->saved_state); 786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void ch7006_encoder_restore(struct drm_encoder *encoder) 816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_state_load(client, &priv->saved_state); 886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder, 91e811f5ae19043b2ac2c28e147a4274038e655598Laurent Pinchart const struct drm_display_mode *mode, 926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_display_mode *adjusted_mode) 936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs /* The ch7006 is painfully picky with the input timings so no 976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * custom modes for now... */ 986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->mode = ch7006_lookup_mode(encoder, mode); 1006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return !!priv->mode; 1026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 1036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_encoder_mode_valid(struct drm_encoder *encoder, 1056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_display_mode *mode) 1066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 1076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (ch7006_lookup_mode(encoder, mode)) 1086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return MODE_OK; 1096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs else 1106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return MODE_BAD; 1116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 1126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void ch7006_encoder_mode_set(struct drm_encoder *encoder, 1146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_display_mode *drm_mode, 1156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_display_mode *adjusted_mode) 1166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 1176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 1186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 1196d6a413aa23c8bc7a5787596e06f3d6d8d4f11c7Francisco Jerez struct ch7006_encoder_params *params = &priv->params; 1206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_state *state = &priv->state; 1216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs uint8_t *regs = state->regs; 1226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_mode *mode = priv->mode; 1236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; 1246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs int start_active; 1256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 1276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode; 1296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_BWIDTH] = 0; 1306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT, 1316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs params->input_format); 1326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK 1346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs | bitf(CH7006_CLKMODE_XCM, params->xcm) 1356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs | bitf(CH7006_CLKMODE_PCM, params->pcm); 1366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (params->clock_mode) 1376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER; 1386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (params->clock_edge) 1396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE; 1406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7); 1426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active); 1436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active); 1446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_INPUT_SYNC] = 0; 1466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (params->sync_direction) 1476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT; 1486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (params->sync_encoding) 1496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED; 1506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC) 1516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC; 1526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC) 1536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC; 1546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_DETECT] = 0; 1566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_BCLKOUT] = 0; 1576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_SUBC_INC3] = 0; 1596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (params->pout_level) 1606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V; 1616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_SUBC_INC4] = 0; 1636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (params->active_detect) 1646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT; 1656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL]; 1676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_levels(encoder); 1696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_subcarrier(encoder); 1706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_pll(encoder); 1716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_power_state(encoder); 1726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_properties(encoder); 1736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_state_load(client, state); 1756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 1766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder, 1786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_connector *connector) 1796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 1806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 1816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 1826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_state *state = &priv->state; 1836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs int det; 1846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 1866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_save_reg(client, state, CH7006_DETECT); 1886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_save_reg(client, state, CH7006_POWER); 1896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_save_reg(client, state, CH7006_CLKMODE); 1906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET | 1926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs bitfs(CH7006_POWER_LEVEL, NORMAL)); 1936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER); 1946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE); 1966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_write(client, CH7006_DETECT, 0); 1986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 1996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs det = ch7006_read(client, CH7006_DETECT); 2006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_CLKMODE); 2026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_POWER); 2036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_DETECT); 2046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| 2066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs CH7006_DETECT_SVIDEO_C_TEST| 2076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs CH7006_DETECT_CVBS_TEST)) == 0) 2086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART; 2096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST| 2106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs CH7006_DETECT_SVIDEO_C_TEST)) == 0) 2116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO; 2126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs else if ((det & CH7006_DETECT_CVBS_TEST) == 0) 2136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite; 2146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs else 2156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; 2166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 217ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_property_set_value(&connector->base, 2186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs encoder->dev->mode_config.tv_subconnector_property, 2196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector); 2206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return priv->subconnector ? connector_status_connected : 2226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs connector_status_disconnected; 2236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 2246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_encoder_get_modes(struct drm_encoder *encoder, 2266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_connector *connector) 2276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 2286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 2296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_mode *mode; 2306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs int n = 0; 2316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs for (mode = ch7006_modes; mode->mode.clock; mode++) { 2336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (~mode->valid_scales & 1<<priv->scale || 2346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ~mode->valid_norms & 1<<priv->norm) 2356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs continue; 2366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_mode_probed_add(connector, 2386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_mode_duplicate(encoder->dev, &mode->mode)); 2396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs n++; 2416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 2426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return n; 2446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 2456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_encoder_create_resources(struct drm_encoder *encoder, 2476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_connector *connector) 2486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 2496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 2506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_device *dev = encoder->dev; 2516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_mode_config *conf = &dev->mode_config; 2526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names); 2546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 255d9bc3c02e36d844c2d980e65ddda5c7699e073f8Sascha Hauer priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2); 2566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 257ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property, 2586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->select_subconnector); 259ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_subconnector_property, 2606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector); 261ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_left_margin_property, 2626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->hmargin); 263ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property, 2646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->vmargin); 265ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_mode_property, 2666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->norm); 267ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_brightness_property, 2686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->brightness); 269ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_contrast_property, 2706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->contrast); 271ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, conf->tv_flicker_reduction_property, 2726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->flicker); 273ec61c71d0dba24efe5868a92f6ba538a50d4823cRob Clark drm_object_attach_property(&connector->base, priv->scale_property, 2746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->scale); 2756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return 0; 2776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 2786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_encoder_set_property(struct drm_encoder *encoder, 2806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_connector *connector, 2816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_property *property, 2826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs uint64_t val) 2836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 2846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct i2c_client *client = drm_i2c_encoder_get_client(encoder); 2856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv = to_ch7006_priv(encoder); 2866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_state *state = &priv->state; 2876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_mode_config *conf = &encoder->dev->mode_config; 2886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_crtc *crtc = encoder->crtc; 2896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs bool modes_changed = false; 2906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 2926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (property == conf->tv_select_subconnector_property) { 2946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->select_subconnector = val; 2956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_power_state(encoder); 2976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 2986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_POWER); 2996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == conf->tv_left_margin_property) { 3016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->hmargin = val; 3026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_properties(encoder); 3046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_POV); 3066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_HPOS); 3076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == conf->tv_bottom_margin_property) { 3096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->vmargin = val; 3106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_properties(encoder); 3126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_POV); 3146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_VPOS); 3156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == conf->tv_mode_property) { 3176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (connector->dpms != DRM_MODE_DPMS_OFF) 3186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return -EINVAL; 3196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->norm = val; 3216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs modes_changed = true; 3236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == conf->tv_brightness_property) { 3256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->brightness = val; 3266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_levels(encoder); 3286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); 3306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == conf->tv_contrast_property) { 3326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->contrast = val; 3336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_properties(encoder); 3356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_CONTRAST); 3376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == conf->tv_flicker_reduction_property) { 3396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->flicker = val; 3406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_setup_properties(encoder); 3426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_load_reg(client, state, CH7006_FFILTER); 3446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else if (property == priv->scale_property) { 3466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (connector->dpms != DRM_MODE_DPMS_OFF) 3476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return -EINVAL; 3486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->scale = val; 3506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs modes_changed = true; 3526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } else { 3546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return -EINVAL; 3556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 3566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (modes_changed) { 3586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_helper_probe_single_connector_modes(connector, 0, 0); 3596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs /* Disable the crtc to ensure a full modeset is 3616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * performed whenever it's turned on again. */ 3626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (crtc) { 3636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_mode_set modeset = { 3646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .crtc = crtc, 3656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs }; 3666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3672d13b6796e420ed00389b7399a5d5ac7b1fed436Daniel Vetter drm_mode_set_config_internal(&modeset); 3686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 3696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 3706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return 0; 3726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 3736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct drm_encoder_slave_funcs ch7006_encoder_funcs = { 3756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .set_config = ch7006_encoder_set_config, 3766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .destroy = ch7006_encoder_destroy, 3776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .dpms = ch7006_encoder_dpms, 3786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .save = ch7006_encoder_save, 3796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .restore = ch7006_encoder_restore, 3806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .mode_fixup = ch7006_encoder_mode_fixup, 3816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .mode_valid = ch7006_encoder_mode_valid, 3826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .mode_set = ch7006_encoder_mode_set, 3836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .detect = ch7006_encoder_detect, 3846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .get_modes = ch7006_encoder_get_modes, 3856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .create_resources = ch7006_encoder_create_resources, 3866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .set_property = ch7006_encoder_set_property, 3876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}; 3886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/* I2C driver functions */ 3916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *id) 3936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 3946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs uint8_t addr = CH7006_VERSION_ID; 3956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs uint8_t val; 3966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs int ret; 3976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 3986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 3996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ret = i2c_master_send(client, &addr, sizeof(addr)); 4016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (ret < 0) 4026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs goto fail; 4036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ret = i2c_master_recv(client, &val, sizeof(val)); 4056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (ret < 0) 4066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs goto fail; 4076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_info(client, "Detected version ID: %x\n", val); 4096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 410dc4a684ae80d914b2b7fe75b2733a3296a8b92d2Francisco Jerez /* I don't know what this is for, but otherwise I get no 411dc4a684ae80d914b2b7fe75b2733a3296a8b92d2Francisco Jerez * signal. 412dc4a684ae80d914b2b7fe75b2733a3296a8b92d2Francisco Jerez */ 413dc4a684ae80d914b2b7fe75b2733a3296a8b92d2Francisco Jerez ch7006_write(client, 0x3d, 0x0); 414dc4a684ae80d914b2b7fe75b2733a3296a8b92d2Francisco Jerez 4156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return 0; 4166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsfail: 4186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_err(client, "Error %d reading version ID\n", ret); 4196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return -ENODEV; 4216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 4226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_remove(struct i2c_client *client) 4246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 4256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 4266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return 0; 4286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 4296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4300227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brownstatic int ch7006_resume(struct device *dev) 4310edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez{ 4320227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brown struct i2c_client *client = to_i2c_client(dev); 4330edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez 4340edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez ch7006_dbg(client, "\n"); 4350edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez 4360edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez ch7006_write(client, 0x3d, 0x0); 4370edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez 4380edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez return 0; 4390edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez} 4400edeb0c024f3af7d4dd8dde44ad1082b265ebc9aFrancisco Jerez 4416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int ch7006_encoder_init(struct i2c_client *client, 4426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_device *dev, 4436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct drm_encoder_slave *encoder) 4446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 4456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs struct ch7006_priv *priv; 4466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs int i; 4476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_dbg(client, "\n"); 4496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv = kzalloc(sizeof(*priv), GFP_KERNEL); 4516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (!priv) 4526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return -ENOMEM; 4536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs encoder->slave_priv = priv; 4556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs encoder->slave_funcs = &ch7006_encoder_funcs; 4566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->norm = TV_NORM_PAL; 4586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic; 4596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; 4606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->scale = 1; 4616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->contrast = 50; 4626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->brightness = 50; 4636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->flicker = 50; 4646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->hmargin = 50; 4656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->vmargin = 50; 4666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->last_dpms = -1; 467c93ebb4021ff1fdffe78be89a4bd30bc7cbc75e6Francisco Jerez priv->chip_version = ch7006_read(client, CH7006_VERSION_ID); 4686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (ch7006_tv_norm) { 4706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs for (i = 0; i < NUM_TV_NORMS; i++) { 4716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (!strcmp(ch7006_tv_norm_names[i], ch7006_tv_norm)) { 4726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->norm = i; 4736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs break; 4746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 4756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 4766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (i == NUM_TV_NORMS) 4786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_err(client, "Invalid TV norm setting \"%s\".\n", 4796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_tv_norm); 4806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs } 4816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs if (ch7006_scale >= 0 && ch7006_scale <= 2) 4836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs priv->scale = ch7006_scale; 4846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs else 4856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_err(client, "Invalid scale setting \"%d\".\n", 4866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs ch7006_scale); 4876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return 0; 4896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 4906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct i2c_device_id ch7006_ids[] = { 4926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs { "ch7006", 0 }, 4936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs { } 4946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}; 4956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_DEVICE_TABLE(i2c, ch7006_ids); 4966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 4970227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brownstatic const struct dev_pm_ops ch7006_pm_ops = { 4980227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brown .resume = ch7006_resume, 4990227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brown}; 5000227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brown 5016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct drm_i2c_encoder_driver ch7006_driver = { 5026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .i2c_driver = { 5036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .probe = ch7006_probe, 5046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .remove = ch7006_remove, 5056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .driver = { 5076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .name = "ch7006", 5080227a7fdc2a4756aa0e0d1152ce5eada016cf18dMark Brown .pm = &ch7006_pm_ops, 5096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs }, 5106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .id_table = ch7006_ids, 5126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs }, 5136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs .encoder_init = ch7006_encoder_init, 5156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}; 5166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/* Module initialization */ 5196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int __init ch7006_init(void) 5216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 5226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver); 5236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 5246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void __exit ch7006_exit(void) 5266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{ 5276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs drm_i2c_encoder_unregister(&ch7006_driver); 5286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} 5296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsint ch7006_debug; 5316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsmodule_param_named(debug, ch7006_debug, int, 0600); 5326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_PARM_DESC(debug, "Enable debug output."); 5336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggschar *ch7006_tv_norm; 5356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsmodule_param_named(tv_norm, ch7006_tv_norm, charp, 0600); 5366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_PARM_DESC(tv_norm, "Default TV norm.\n" 5376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n" 5386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs "\t\tDefault: PAL"); 5396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsint ch7006_scale = 1; 5416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsmodule_param_named(scale, ch7006_scale, int, 0600); 5426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_PARM_DESC(scale, "Default scale.\n" 5436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n" 5446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs "\t\t\t1 -> Select default video modes.\n" 5456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs "\t\t\t2 -> Select video modes with a lower blanking ratio."); 5466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>"); 5486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver"); 5496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben SkeggsMODULE_LICENSE("GPL and additional rights"); 5506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs 5516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsmodule_init(ch7006_init); 5526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsmodule_exit(ch7006_exit); 553