Ben Skeggs | 6ee7386 | 2009-12-11 19:24:15 +1000 | [diff] [blame] | 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 "ch7006_priv.h" |
| 28 | |
| 29 | char *ch7006_tv_norm_names[] = { |
| 30 | [TV_NORM_PAL] = "PAL", |
| 31 | [TV_NORM_PAL_M] = "PAL-M", |
| 32 | [TV_NORM_PAL_N] = "PAL-N", |
| 33 | [TV_NORM_PAL_NC] = "PAL-Nc", |
| 34 | [TV_NORM_PAL_60] = "PAL-60", |
| 35 | [TV_NORM_NTSC_M] = "NTSC-M", |
| 36 | [TV_NORM_NTSC_J] = "NTSC-J", |
| 37 | }; |
| 38 | |
| 39 | #define NTSC_LIKE_TIMINGS .vrefresh = 60 * fixed1/1.001, \ |
| 40 | .vdisplay = 480, \ |
| 41 | .vtotal = 525, \ |
| 42 | .hvirtual = 660 |
| 43 | |
| 44 | #define PAL_LIKE_TIMINGS .vrefresh = 50 * fixed1, \ |
| 45 | .vdisplay = 576, \ |
| 46 | .vtotal = 625, \ |
| 47 | .hvirtual = 810 |
| 48 | |
| 49 | struct ch7006_tv_norm_info ch7006_tv_norms[] = { |
| 50 | [TV_NORM_NTSC_M] = { |
| 51 | NTSC_LIKE_TIMINGS, |
| 52 | .black_level = 0.339 * fixed1, |
| 53 | .subc_freq = 3579545 * fixed1, |
| 54 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC), |
| 55 | .voffset = 0, |
| 56 | }, |
| 57 | [TV_NORM_NTSC_J] = { |
| 58 | NTSC_LIKE_TIMINGS, |
| 59 | .black_level = 0.286 * fixed1, |
| 60 | .subc_freq = 3579545 * fixed1, |
| 61 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC_J), |
| 62 | .voffset = 0, |
| 63 | }, |
| 64 | [TV_NORM_PAL] = { |
| 65 | PAL_LIKE_TIMINGS, |
| 66 | .black_level = 0.3 * fixed1, |
| 67 | .subc_freq = 4433618.75 * fixed1, |
| 68 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), |
| 69 | .voffset = 0, |
| 70 | }, |
| 71 | [TV_NORM_PAL_M] = { |
| 72 | NTSC_LIKE_TIMINGS, |
| 73 | .black_level = 0.339 * fixed1, |
| 74 | .subc_freq = 3575611.433 * fixed1, |
| 75 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), |
| 76 | .voffset = 16, |
| 77 | }, |
| 78 | |
| 79 | /* The following modes seem to work right but they're |
| 80 | * undocumented */ |
| 81 | |
| 82 | [TV_NORM_PAL_N] = { |
| 83 | PAL_LIKE_TIMINGS, |
| 84 | .black_level = 0.339 * fixed1, |
| 85 | .subc_freq = 4433618.75 * fixed1, |
| 86 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), |
| 87 | .voffset = 0, |
| 88 | }, |
| 89 | [TV_NORM_PAL_NC] = { |
| 90 | PAL_LIKE_TIMINGS, |
| 91 | .black_level = 0.3 * fixed1, |
| 92 | .subc_freq = 3582056.25 * fixed1, |
| 93 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL), |
| 94 | .voffset = 0, |
| 95 | }, |
| 96 | [TV_NORM_PAL_60] = { |
| 97 | NTSC_LIKE_TIMINGS, |
| 98 | .black_level = 0.3 * fixed1, |
| 99 | .subc_freq = 4433618.75 * fixed1, |
| 100 | .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M), |
| 101 | .voffset = 16, |
| 102 | }, |
| 103 | }; |
| 104 | |
| 105 | #define __MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ |
| 106 | subc, scale, scale_mask, norm_mask, e_hd, e_vd) { \ |
| 107 | .mode = { \ |
| 108 | .name = #hd "x" #vd, \ |
| 109 | .status = 0, \ |
| 110 | .type = DRM_MODE_TYPE_DRIVER, \ |
| 111 | .clock = f, \ |
| 112 | .hdisplay = hd, \ |
| 113 | .hsync_start = e_hd + 16, \ |
| 114 | .hsync_end = e_hd + 80, \ |
| 115 | .htotal = ht, \ |
| 116 | .hskew = 0, \ |
| 117 | .vdisplay = vd, \ |
| 118 | .vsync_start = vd + 10, \ |
| 119 | .vsync_end = vd + 26, \ |
| 120 | .vtotal = vt, \ |
| 121 | .vscan = 0, \ |
| 122 | .flags = DRM_MODE_FLAG_##hsynp##HSYNC | \ |
| 123 | DRM_MODE_FLAG_##vsynp##VSYNC, \ |
| 124 | .vrefresh = 0, \ |
| 125 | }, \ |
| 126 | .enc_hdisp = e_hd, \ |
| 127 | .enc_vdisp = e_vd, \ |
| 128 | .subc_coeff = subc * fixed1, \ |
| 129 | .dispmode = bitfs(CH7006_DISPMODE_SCALING_RATIO, scale) | \ |
| 130 | bitfs(CH7006_DISPMODE_INPUT_RES, e_hd##x##e_vd), \ |
| 131 | .valid_scales = scale_mask, \ |
| 132 | .valid_norms = norm_mask \ |
| 133 | } |
| 134 | |
| 135 | #define MODE(f, hd, vd, ht, vt, hsynp, vsynp, \ |
| 136 | subc, scale, scale_mask, norm_mask) \ |
| 137 | __MODE(f, hd, vd, ht, vt, hsynp, vsynp, subc, scale, \ |
| 138 | scale_mask, norm_mask, hd, vd) |
| 139 | |
| 140 | #define NTSC_LIKE (1 << TV_NORM_NTSC_M | 1 << TV_NORM_NTSC_J | \ |
| 141 | 1 << TV_NORM_PAL_M | 1 << TV_NORM_PAL_60) |
| 142 | |
| 143 | #define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC) |
| 144 | |
| 145 | struct ch7006_mode ch7006_modes[] = { |
| 146 | MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE), |
| 147 | MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE), |
| 148 | MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE), |
| 149 | MODE(24671, 512, 384, 784, 525, N, N, 174.0874153, 1_1, 0x3, NTSC_LIKE), |
| 150 | MODE(28125, 720, 400, 1125, 500, N, N, 135.742176298, 5_4, 0x6, PAL_LIKE), |
| 151 | MODE(34875, 720, 400, 1116, 625, N, N, 109.469496898, 1_1, 0x1, PAL_LIKE), |
| 152 | MODE(23790, 720, 400, 945, 420, N, N, 160.475642016, 5_4, 0x4, NTSC_LIKE), |
| 153 | MODE(29455, 720, 400, 936, 525, N, N, 129.614941843, 1_1, 0x3, NTSC_LIKE), |
| 154 | MODE(25000, 640, 400, 1000, 500, N, N, 152.709948279, 5_4, 0x6, PAL_LIKE), |
| 155 | MODE(31500, 640, 400, 1008, 625, N, N, 121.198371646, 1_1, 0x1, PAL_LIKE), |
| 156 | MODE(21147, 640, 400, 840, 420, N, N, 180.535097338, 5_4, 0x4, NTSC_LIKE), |
| 157 | MODE(26434, 640, 400, 840, 525, N, N, 144.42807787, 1_1, 0x2, NTSC_LIKE), |
| 158 | MODE(30210, 640, 400, 840, 600, N, N, 126.374568276, 7_8, 0x1, NTSC_LIKE), |
| 159 | MODE(21000, 640, 480, 840, 500, N, N, 181.797557582, 5_4, 0x4, PAL_LIKE), |
| 160 | MODE(26250, 640, 480, 840, 625, N, N, 145.438046066, 1_1, 0x2, PAL_LIKE), |
| 161 | MODE(31500, 640, 480, 840, 750, N, N, 121.198371646, 5_6, 0x1, PAL_LIKE), |
| 162 | MODE(24671, 640, 480, 784, 525, N, N, 174.0874153, 1_1, 0x4, NTSC_LIKE), |
| 163 | MODE(28196, 640, 480, 784, 600, N, N, 152.326488422, 7_8, 0x2, NTSC_LIKE), |
| 164 | MODE(30210, 640, 480, 800, 630, N, N, 142.171389101, 5_6, 0x1, NTSC_LIKE), |
| 165 | __MODE(29500, 720, 576, 944, 625, P, P, 145.592111636, 1_1, 0x7, PAL_LIKE, 800, 600), |
| 166 | MODE(36000, 800, 600, 960, 750, P, P, 119.304647022, 5_6, 0x6, PAL_LIKE), |
| 167 | MODE(39000, 800, 600, 936, 836, P, P, 110.127366499, 3_4, 0x1, PAL_LIKE), |
| 168 | MODE(39273, 800, 600, 1040, 630, P, P, 145.816809399, 5_6, 0x4, NTSC_LIKE), |
| 169 | MODE(43636, 800, 600, 1040, 700, P, P, 131.235128487, 3_4, 0x2, NTSC_LIKE), |
| 170 | MODE(47832, 800, 600, 1064, 750, P, P, 119.723275165, 7_10, 0x1, NTSC_LIKE), |
| 171 | {} |
| 172 | }; |
| 173 | |
| 174 | struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder, |
Laurent Pinchart | e811f5a | 2012-07-17 17:56:50 +0200 | [diff] [blame] | 175 | const struct drm_display_mode *drm_mode) |
Ben Skeggs | 6ee7386 | 2009-12-11 19:24:15 +1000 | [diff] [blame] | 176 | { |
| 177 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 178 | struct ch7006_mode *mode; |
| 179 | |
| 180 | for (mode = ch7006_modes; mode->mode.clock; mode++) { |
| 181 | |
| 182 | if (~mode->valid_norms & 1<<priv->norm) |
| 183 | continue; |
| 184 | |
| 185 | if (mode->mode.hdisplay != drm_mode->hdisplay || |
| 186 | mode->mode.vdisplay != drm_mode->vdisplay || |
| 187 | mode->mode.vtotal != drm_mode->vtotal || |
| 188 | mode->mode.htotal != drm_mode->htotal || |
| 189 | mode->mode.clock != drm_mode->clock) |
| 190 | continue; |
| 191 | |
| 192 | return mode; |
| 193 | } |
| 194 | |
| 195 | return NULL; |
| 196 | } |
| 197 | |
| 198 | /* Some common HW state calculation code */ |
| 199 | |
| 200 | void ch7006_setup_levels(struct drm_encoder *encoder) |
| 201 | { |
| 202 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 203 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 204 | uint8_t *regs = priv->state.regs; |
| 205 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 206 | int gain; |
| 207 | int black_level; |
| 208 | |
| 209 | /* Set DAC_GAIN if the voltage drop between white and black is |
| 210 | * high enough. */ |
| 211 | if (norm->black_level < 339*fixed1/1000) { |
| 212 | gain = 76; |
| 213 | |
| 214 | regs[CH7006_INPUT_FORMAT] |= CH7006_INPUT_FORMAT_DAC_GAIN; |
| 215 | } else { |
| 216 | gain = 71; |
| 217 | |
| 218 | regs[CH7006_INPUT_FORMAT] &= ~CH7006_INPUT_FORMAT_DAC_GAIN; |
| 219 | } |
| 220 | |
| 221 | black_level = round_fixed(norm->black_level*26625)/gain; |
| 222 | |
| 223 | /* Correct it with the specified brightness. */ |
| 224 | black_level = interpolate(90, black_level, 208, priv->brightness); |
| 225 | |
| 226 | regs[CH7006_BLACK_LEVEL] = bitf(CH7006_BLACK_LEVEL_0, black_level); |
| 227 | |
| 228 | ch7006_dbg(client, "black level: %d\n", black_level); |
| 229 | } |
| 230 | |
| 231 | void ch7006_setup_subcarrier(struct drm_encoder *encoder) |
| 232 | { |
| 233 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 234 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 235 | struct ch7006_state *state = &priv->state; |
| 236 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 237 | struct ch7006_mode *mode = priv->mode; |
| 238 | uint32_t subc_inc; |
| 239 | |
| 240 | subc_inc = round_fixed((mode->subc_coeff >> 8) |
| 241 | * (norm->subc_freq >> 24)); |
| 242 | |
| 243 | setbitf(state, CH7006_SUBC_INC0, 28, subc_inc); |
| 244 | setbitf(state, CH7006_SUBC_INC1, 24, subc_inc); |
| 245 | setbitf(state, CH7006_SUBC_INC2, 20, subc_inc); |
| 246 | setbitf(state, CH7006_SUBC_INC3, 16, subc_inc); |
| 247 | setbitf(state, CH7006_SUBC_INC4, 12, subc_inc); |
| 248 | setbitf(state, CH7006_SUBC_INC5, 8, subc_inc); |
| 249 | setbitf(state, CH7006_SUBC_INC6, 4, subc_inc); |
| 250 | setbitf(state, CH7006_SUBC_INC7, 0, subc_inc); |
| 251 | |
| 252 | ch7006_dbg(client, "subcarrier inc: %u\n", subc_inc); |
| 253 | } |
| 254 | |
| 255 | void ch7006_setup_pll(struct drm_encoder *encoder) |
| 256 | { |
| 257 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 258 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 259 | uint8_t *regs = priv->state.regs; |
| 260 | struct ch7006_mode *mode = priv->mode; |
| 261 | int n, best_n = 0; |
| 262 | int m, best_m = 0; |
| 263 | int freq, best_freq = 0; |
| 264 | |
| 265 | for (n = 0; n < CH7006_MAXN; n++) { |
| 266 | for (m = 0; m < CH7006_MAXM; m++) { |
| 267 | freq = CH7006_FREQ0*(n+2)/(m+2); |
| 268 | |
| 269 | if (abs(freq - mode->mode.clock) < |
| 270 | abs(best_freq - mode->mode.clock)) { |
| 271 | best_freq = freq; |
| 272 | best_n = n; |
| 273 | best_m = m; |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | regs[CH7006_PLLOV] = bitf(CH7006_PLLOV_N_8, best_n) | |
| 279 | bitf(CH7006_PLLOV_M_8, best_m); |
| 280 | |
| 281 | regs[CH7006_PLLM] = bitf(CH7006_PLLM_0, best_m); |
| 282 | regs[CH7006_PLLN] = bitf(CH7006_PLLN_0, best_n); |
| 283 | |
| 284 | if (best_n < 108) |
| 285 | regs[CH7006_PLL_CONTROL] |= CH7006_PLL_CONTROL_CAPACITOR; |
| 286 | else |
| 287 | regs[CH7006_PLL_CONTROL] &= ~CH7006_PLL_CONTROL_CAPACITOR; |
| 288 | |
| 289 | ch7006_dbg(client, "n=%d m=%d f=%d c=%d\n", |
| 290 | best_n, best_m, best_freq, best_n < 108); |
| 291 | } |
| 292 | |
| 293 | void ch7006_setup_power_state(struct drm_encoder *encoder) |
| 294 | { |
| 295 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 296 | uint8_t *power = &priv->state.regs[CH7006_POWER]; |
| 297 | int subconnector; |
| 298 | |
| 299 | subconnector = priv->select_subconnector ? priv->select_subconnector : |
| 300 | priv->subconnector; |
| 301 | |
| 302 | *power = CH7006_POWER_RESET; |
| 303 | |
| 304 | if (priv->last_dpms == DRM_MODE_DPMS_ON) { |
| 305 | switch (subconnector) { |
| 306 | case DRM_MODE_SUBCONNECTOR_SVIDEO: |
| 307 | *power |= bitfs(CH7006_POWER_LEVEL, CVBS_OFF); |
| 308 | break; |
| 309 | case DRM_MODE_SUBCONNECTOR_Composite: |
| 310 | *power |= bitfs(CH7006_POWER_LEVEL, SVIDEO_OFF); |
| 311 | break; |
| 312 | case DRM_MODE_SUBCONNECTOR_SCART: |
| 313 | *power |= bitfs(CH7006_POWER_LEVEL, NORMAL) | |
| 314 | CH7006_POWER_SCART; |
| 315 | break; |
| 316 | } |
| 317 | |
| 318 | } else { |
Francisco Jerez | c93ebb4 | 2010-08-05 22:57:08 +0200 | [diff] [blame] | 319 | if (priv->chip_version >= 0x20) |
| 320 | *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); |
| 321 | else |
| 322 | *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF); |
Ben Skeggs | 6ee7386 | 2009-12-11 19:24:15 +1000 | [diff] [blame] | 323 | } |
| 324 | } |
| 325 | |
| 326 | void ch7006_setup_properties(struct drm_encoder *encoder) |
| 327 | { |
| 328 | struct i2c_client *client = drm_i2c_encoder_get_client(encoder); |
| 329 | struct ch7006_priv *priv = to_ch7006_priv(encoder); |
| 330 | struct ch7006_state *state = &priv->state; |
| 331 | struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm]; |
| 332 | struct ch7006_mode *ch_mode = priv->mode; |
| 333 | struct drm_display_mode *mode = &ch_mode->mode; |
| 334 | uint8_t *regs = state->regs; |
| 335 | int flicker, contrast, hpos, vpos; |
| 336 | uint64_t scale, aspect; |
| 337 | |
| 338 | flicker = interpolate(0, 2, 3, priv->flicker); |
| 339 | regs[CH7006_FFILTER] = bitf(CH7006_FFILTER_TEXT, flicker) | |
| 340 | bitf(CH7006_FFILTER_LUMA, flicker) | |
| 341 | bitf(CH7006_FFILTER_CHROMA, 1); |
| 342 | |
| 343 | contrast = interpolate(0, 5, 7, priv->contrast); |
| 344 | regs[CH7006_CONTRAST] = bitf(CH7006_CONTRAST_0, contrast); |
| 345 | |
| 346 | scale = norm->vtotal*fixed1; |
| 347 | do_div(scale, mode->vtotal); |
| 348 | |
| 349 | aspect = ch_mode->enc_hdisp*fixed1; |
| 350 | do_div(aspect, ch_mode->enc_vdisp); |
| 351 | |
| 352 | hpos = round_fixed((norm->hvirtual * aspect - mode->hdisplay * scale) |
| 353 | * priv->hmargin * mode->vtotal) / norm->vtotal / 100 / 4; |
| 354 | |
| 355 | setbitf(state, CH7006_POV, HPOS_8, hpos); |
| 356 | setbitf(state, CH7006_HPOS, 0, hpos); |
| 357 | |
| 358 | vpos = max(0, norm->vdisplay - round_fixed(mode->vdisplay*scale) |
| 359 | + norm->voffset) * priv->vmargin / 100 / 2; |
| 360 | |
| 361 | setbitf(state, CH7006_POV, VPOS_8, vpos); |
| 362 | setbitf(state, CH7006_VPOS, 0, vpos); |
| 363 | |
| 364 | ch7006_dbg(client, "hpos: %d, vpos: %d\n", hpos, vpos); |
| 365 | } |
| 366 | |
| 367 | /* HW access functions */ |
| 368 | |
| 369 | void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val) |
| 370 | { |
| 371 | uint8_t buf[] = {addr, val}; |
| 372 | int ret; |
| 373 | |
| 374 | ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); |
| 375 | if (ret < 0) |
| 376 | ch7006_err(client, "Error %d writing to subaddress 0x%x\n", |
| 377 | ret, addr); |
| 378 | } |
| 379 | |
| 380 | uint8_t ch7006_read(struct i2c_client *client, uint8_t addr) |
| 381 | { |
| 382 | uint8_t val; |
| 383 | int ret; |
| 384 | |
| 385 | ret = i2c_master_send(client, &addr, sizeof(addr)); |
| 386 | if (ret < 0) |
| 387 | goto fail; |
| 388 | |
| 389 | ret = i2c_master_recv(client, &val, sizeof(val)); |
| 390 | if (ret < 0) |
| 391 | goto fail; |
| 392 | |
| 393 | return val; |
| 394 | |
| 395 | fail: |
| 396 | ch7006_err(client, "Error %d reading from subaddress 0x%x\n", |
| 397 | ret, addr); |
| 398 | return 0; |
| 399 | } |
| 400 | |
| 401 | void ch7006_state_load(struct i2c_client *client, |
| 402 | struct ch7006_state *state) |
| 403 | { |
| 404 | ch7006_load_reg(client, state, CH7006_POWER); |
| 405 | |
| 406 | ch7006_load_reg(client, state, CH7006_DISPMODE); |
| 407 | ch7006_load_reg(client, state, CH7006_FFILTER); |
| 408 | ch7006_load_reg(client, state, CH7006_BWIDTH); |
| 409 | ch7006_load_reg(client, state, CH7006_INPUT_FORMAT); |
| 410 | ch7006_load_reg(client, state, CH7006_CLKMODE); |
| 411 | ch7006_load_reg(client, state, CH7006_START_ACTIVE); |
| 412 | ch7006_load_reg(client, state, CH7006_POV); |
| 413 | ch7006_load_reg(client, state, CH7006_BLACK_LEVEL); |
| 414 | ch7006_load_reg(client, state, CH7006_HPOS); |
| 415 | ch7006_load_reg(client, state, CH7006_VPOS); |
| 416 | ch7006_load_reg(client, state, CH7006_INPUT_SYNC); |
| 417 | ch7006_load_reg(client, state, CH7006_DETECT); |
| 418 | ch7006_load_reg(client, state, CH7006_CONTRAST); |
| 419 | ch7006_load_reg(client, state, CH7006_PLLOV); |
| 420 | ch7006_load_reg(client, state, CH7006_PLLM); |
| 421 | ch7006_load_reg(client, state, CH7006_PLLN); |
| 422 | ch7006_load_reg(client, state, CH7006_BCLKOUT); |
| 423 | ch7006_load_reg(client, state, CH7006_SUBC_INC0); |
| 424 | ch7006_load_reg(client, state, CH7006_SUBC_INC1); |
| 425 | ch7006_load_reg(client, state, CH7006_SUBC_INC2); |
| 426 | ch7006_load_reg(client, state, CH7006_SUBC_INC3); |
| 427 | ch7006_load_reg(client, state, CH7006_SUBC_INC4); |
| 428 | ch7006_load_reg(client, state, CH7006_SUBC_INC5); |
| 429 | ch7006_load_reg(client, state, CH7006_SUBC_INC6); |
| 430 | ch7006_load_reg(client, state, CH7006_SUBC_INC7); |
| 431 | ch7006_load_reg(client, state, CH7006_PLL_CONTROL); |
| 432 | ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0); |
Ben Skeggs | 6ee7386 | 2009-12-11 19:24:15 +1000 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | void ch7006_state_save(struct i2c_client *client, |
| 436 | struct ch7006_state *state) |
| 437 | { |
| 438 | ch7006_save_reg(client, state, CH7006_POWER); |
| 439 | |
| 440 | ch7006_save_reg(client, state, CH7006_DISPMODE); |
| 441 | ch7006_save_reg(client, state, CH7006_FFILTER); |
| 442 | ch7006_save_reg(client, state, CH7006_BWIDTH); |
| 443 | ch7006_save_reg(client, state, CH7006_INPUT_FORMAT); |
| 444 | ch7006_save_reg(client, state, CH7006_CLKMODE); |
| 445 | ch7006_save_reg(client, state, CH7006_START_ACTIVE); |
| 446 | ch7006_save_reg(client, state, CH7006_POV); |
| 447 | ch7006_save_reg(client, state, CH7006_BLACK_LEVEL); |
| 448 | ch7006_save_reg(client, state, CH7006_HPOS); |
| 449 | ch7006_save_reg(client, state, CH7006_VPOS); |
| 450 | ch7006_save_reg(client, state, CH7006_INPUT_SYNC); |
| 451 | ch7006_save_reg(client, state, CH7006_DETECT); |
| 452 | ch7006_save_reg(client, state, CH7006_CONTRAST); |
| 453 | ch7006_save_reg(client, state, CH7006_PLLOV); |
| 454 | ch7006_save_reg(client, state, CH7006_PLLM); |
| 455 | ch7006_save_reg(client, state, CH7006_PLLN); |
| 456 | ch7006_save_reg(client, state, CH7006_BCLKOUT); |
| 457 | ch7006_save_reg(client, state, CH7006_SUBC_INC0); |
| 458 | ch7006_save_reg(client, state, CH7006_SUBC_INC1); |
| 459 | ch7006_save_reg(client, state, CH7006_SUBC_INC2); |
| 460 | ch7006_save_reg(client, state, CH7006_SUBC_INC3); |
| 461 | ch7006_save_reg(client, state, CH7006_SUBC_INC4); |
| 462 | ch7006_save_reg(client, state, CH7006_SUBC_INC5); |
| 463 | ch7006_save_reg(client, state, CH7006_SUBC_INC6); |
| 464 | ch7006_save_reg(client, state, CH7006_SUBC_INC7); |
| 465 | ch7006_save_reg(client, state, CH7006_PLL_CONTROL); |
| 466 | ch7006_save_reg(client, state, CH7006_CALC_SUBC_INC0); |
| 467 | |
| 468 | state->regs[CH7006_FFILTER] = (state->regs[CH7006_FFILTER] & 0xf0) | |
| 469 | (state->regs[CH7006_FFILTER] & 0x0c) >> 2 | |
| 470 | (state->regs[CH7006_FFILTER] & 0x03) << 2; |
| 471 | } |