179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/* 279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Copyright © 2006 Intel Corporation 379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * 479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Permission is hereby granted, free of charge, to any person obtaining a 579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * copy of this software and associated documentation files (the "Software"), 679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * to deal in the Software without restriction, including without limitation 779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * the rights to use, copy, modify, merge, publish, distribute, sublicense, 879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * and/or sell copies of the Software, and to permit persons to whom the 979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Software is furnished to do so, subject to the following conditions: 1079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * 1179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * The above copyright notice and this permission notice (including the next 1279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * paragraph) shall be included in all copies or substantial portions of the 1379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Software. 1479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * 1579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * DEALINGS IN THE SOFTWARE. 2279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * 2379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Authors: 2479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Eric Anholt <eric@anholt.net> 2579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * 2679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes */ 2779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 2879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#include "dvo.h" 2979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 3079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TV_DISPLAY_MODE 0x00 3179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_FLICKER_FILTER 0x01 3279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_VIDEO_BANDWIDTH 0x02 3379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TEXT_ENHANCEMENT 0x03 3479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_START_ACTIVE_VIDEO 0x04 3579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_HORIZONTAL_POSITION 0x05 3679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_VERTICAL_POSITION 0x06 3779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_BLACK_LEVEL 0x07 3879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_CONTRAST_ENHANCEMENT 0x08 3979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TV_PLL 0x09 4079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TV_PLL_M 0x0a 4179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TV_PLL_N 0x0b 4279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_SUB_CARRIER_0 0x0c 4379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_CIV_CONTROL 0x10 4479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_CIV_0 0x11 4579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_CHROMA_BOOST 0x14 4679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_CLOCK_MODE 0x1c 4779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_INPUT_CLOCK 0x1d 4879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_GPIO_CONTROL 0x1e 4979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_INPUT_DATA_FORMAT 0x1f 5079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_CONNECTION_DETECT 0x20 5179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DAC_CONTROL 0x21 5279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 5379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DEFEAT_VSYNC 0x47 5479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TEST_PATTERN 0x48 5579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 5679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_POWER_MANAGEMENT 0x49 5779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Enables the TV output path. */ 5879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TV_EN (1 << 0) 5979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DAC0_POWER_DOWN (1 << 1) 6079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DAC1_POWER_DOWN (1 << 2) 6179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DAC2_POWER_DOWN (1 << 3) 6279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DAC3_POWER_DOWN (1 << 4) 6379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Powers down the TV out block, and DAC0-3 */ 6479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_TV_POWER_DOWN_EN (1 << 5) 6579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 6679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_VERSION_ID 0x4a 6779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 6879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DEVICE_ID 0x4b 6979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_DEVICE_ID_VALUE 0x1b 7079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7018_DEVICE_ID_VALUE 0x1a 7179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7019_DEVICE_ID_VALUE 0x19 7279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 7379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_XCLK_D2_ADJUST 0x53 7479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_COEFF_0 0x55 7579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_COEFF_1 0x56 7679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_COEFF_2 0x57 7779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_COEFF_3 0x58 7879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_COEFF_4 0x59 7979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a 8079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b 8179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_GPIO_INVERT 0x5c 8279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d 8379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e 8479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 8579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f 8679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/**< Low bits of horizontal active pixel input */ 8779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 8879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 8979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** High bits of horizontal active pixel input */ 9079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) 9179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** High bits of vertical active line output */ 9279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) 9379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 9479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 9579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/**< Low bits of vertical active line output */ 9679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 9779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 9879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/**< Low bits of horizontal active pixel output */ 9979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 10079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_POWER_DOWN 0x63 10179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** High bits of horizontal active pixel output */ 10279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) 10379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Enables the LVDS power down state transition */ 10479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_POWER_DOWN_EN (1 << 6) 10579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Enables the LVDS upscaler */ 10679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_UPSCALER_EN (1 << 7) 10779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 10879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 10979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_ENCODING 0x64 11079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_DITHER_2D (1 << 2) 11179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_DITHER_DIS (1 << 3) 11279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) 11379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_24_BIT (1 << 5) 11479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 11579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_ENCODING_2 0x65 11679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 11779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_PLL_CONTROL 0x66 11879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Enables the LVDS panel output path */ 11979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_PANEN (1 << 0) 12079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Enables the LVDS panel backlight */ 12179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_BKLEN (1 << 3) 12279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 12379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_POWER_SEQUENCING_T1 0x67 12479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_POWER_SEQUENCING_T2 0x68 12579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_POWER_SEQUENCING_T3 0x69 12679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_POWER_SEQUENCING_T4 0x6a 12779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_POWER_SEQUENCING_T5 0x6b 12879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_GPIO_DRIVER_TYPE 0x6c 12979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_GPIO_DATA 0x6d 13079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_GPIO_DIRECTION_CONTROL 0x6e 13179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 13279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 13379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 13479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 13579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 13679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 13779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_PLL_VCO_CONTROL 0x72 13879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 13979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_PLL_VCO_SHIFT 4 14079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 14179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 14279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_OUTPUTS_ENABLE 0x73 14379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_CHARGE_PUMP_LOW 0x0 14479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_CHARGE_PUMP_HIGH 0x3 14579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_CHANNEL_A (1 << 3) 14679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LVDS_CHANNEL_B (1 << 4) 14779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_TV_DAC_A (1 << 5) 14879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_TV_DAC_B (1 << 6) 14979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_DDC_SELECT_DC2 (1 << 7) 15079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 15179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 15279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 15379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 15479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 15579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_LVDS_CONTROL_2 0x78 15679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_LOOP_FILTER_SHIFT 5 15779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes# define CH7017_PHASE_DETECTOR_SHIFT 0 15879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 15979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define CH7017_BANG_LIMIT_CONTROL 0x7f 16079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 16179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstruct ch7017_priv { 1626443170f6d862a1cc89e61e4bb2410b714b875f4Eric Anholt uint8_t dummy; 16379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes}; 16479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 16579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic void ch7017_dump_regs(struct intel_dvo_device *dvo); 16679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic void ch7017_dpms(struct intel_dvo_device *dvo, int mode); 16779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 168a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilsonstatic bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val) 16979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 17079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct i2c_msg msgs[] = { 17179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes { 172f9c10a9b96a31b4a82a4fa807400c04f00284068Keith Packard .addr = dvo->slave_addr, 17379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .flags = 0, 17479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .len = 1, 175a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson .buf = &addr, 17679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes }, 17779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes { 178f9c10a9b96a31b4a82a4fa807400c04f00284068Keith Packard .addr = dvo->slave_addr, 17979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .flags = I2C_M_RD, 18079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .len = 1, 181a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson .buf = val, 18279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } 18379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes }; 184a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2; 18579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 18679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 187a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilsonstatic bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) 18879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 189a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson uint8_t buf[2] = { addr, val }; 19079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct i2c_msg msg = { 191f9c10a9b96a31b4a82a4fa807400c04f00284068Keith Packard .addr = dvo->slave_addr, 19279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .flags = 0, 19379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .len = 2, 194a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson .buf = buf, 19579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes }; 196a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1; 19779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 19879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 19979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/** Probes for a CH7017 on the given bus and slave address. */ 20079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic bool ch7017_init(struct intel_dvo_device *dvo, 201f9c10a9b96a31b4a82a4fa807400c04f00284068Keith Packard struct i2c_adapter *adapter) 20279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 20379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct ch7017_priv *priv; 204a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson const char *str; 205a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson u8 val; 20679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 20779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); 20879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (priv == NULL) 20979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes return false; 21079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 211f9c10a9b96a31b4a82a4fa807400c04f00284068Keith Packard dvo->i2c_bus = adapter; 21279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes dvo->dev_priv = priv; 21379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 21479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) 21579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes goto fail; 21679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 217a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson switch (val) { 218a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson case CH7017_DEVICE_ID_VALUE: 219a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson str = "ch7017"; 220a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson break; 221a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson case CH7018_DEVICE_ID_VALUE: 222a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson str = "ch7018"; 223a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson break; 224a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson case CH7019_DEVICE_ID_VALUE: 225a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson str = "ch7019"; 226a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson break; 227a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson default: 228d0c3b04ae953fd3bf69f9b1430c22608d2d3b90dZhao Yakui DRM_DEBUG_KMS("ch701x not detected, got %d: from %s " 229a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson "slave %d.\n", 2300206e353a0416ad63ce07f53c807c2c725633b87Akshay Joshi val, adapter->name, dvo->slave_addr); 23179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes goto fail; 23279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } 23379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 234a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson DRM_DEBUG_KMS("%s detected on %s, addr %d\n", 235a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson str, adapter->name, dvo->slave_addr); 23679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes return true; 237a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson 23879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesfail: 23979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes kfree(priv); 24079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes return false; 24179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 24279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 24379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) 24479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 245cc6455f82edd3f9da3b03870d41cde3cb22ad40dChris Wilson return connector_status_connected; 24679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 24779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 24879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, 24979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct drm_display_mode *mode) 25079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 25179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (mode->clock > 160000) 25279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes return MODE_CLOCK_HIGH; 25379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 25479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes return MODE_OK; 25579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 25679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 25779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic void ch7017_mode_set(struct intel_dvo_device *dvo, 25879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct drm_display_mode *mode, 25979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct drm_display_mode *adjusted_mode) 26079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 26179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; 26279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t outputs_enable, lvds_control_2, lvds_power_down; 26379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t horizontal_active_pixel_input; 26479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t horizontal_active_pixel_output, vertical_active_line_output; 26579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t active_input_line_output; 26679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 267d0c3b04ae953fd3bf69f9b1430c22608d2d3b90dZhao Yakui DRM_DEBUG_KMS("Registers before mode setting\n"); 26879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_dump_regs(dvo); 26979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 27079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ 27179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (mode->clock < 100000) { 27279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; 27379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | 27479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | 27579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); 27679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | 27779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (2 << CH7017_LVDS_PLL_VCO_SHIFT) | 27879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); 27979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | 28079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (0 << CH7017_PHASE_DETECTOR_SHIFT); 28179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } else { 28279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; 28379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | 28479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | 28579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); 28679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_pll_feedback_div = 35; 28779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | 28879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (0 << CH7017_PHASE_DETECTOR_SHIFT); 28979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ 29079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes outputs_enable |= CH7017_LVDS_CHANNEL_B; 29179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | 29279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (2 << CH7017_LVDS_PLL_VCO_SHIFT) | 29379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); 29479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } else { 29579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | 29679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (1 << CH7017_LVDS_PLL_VCO_SHIFT) | 29779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); 29879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } 29979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } 30079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 30179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes horizontal_active_pixel_input = mode->hdisplay & 0x00ff; 30279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 30379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes vertical_active_line_output = mode->vdisplay & 0x00ff; 30479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes horizontal_active_pixel_output = mode->hdisplay & 0x00ff; 30579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 30679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | 30779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (((mode->vdisplay & 0x0700) >> 8) << 3); 30879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 30979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | 31079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes (mode->hdisplay & 0x0700) >> 8; 31179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 31279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); 31379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, 31479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes horizontal_active_pixel_input); 31579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, 31679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes horizontal_active_pixel_output); 31779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, 31879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes vertical_active_line_output); 31979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, 32079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes active_input_line_output); 32179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); 32279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); 32379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); 32479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); 32579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 32679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes /* Turn the LVDS back on with new settings. */ 32779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); 32879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 329d0c3b04ae953fd3bf69f9b1430c22608d2d3b90dZhao Yakui DRM_DEBUG_KMS("Registers after mode setting\n"); 33079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_dump_regs(dvo); 33179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 33279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 33379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes/* set the CH7017 power state */ 33479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic void ch7017_dpms(struct intel_dvo_device *dvo, int mode) 33579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 33679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t val; 33779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 33879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); 33979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 34079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes /* Turn off TV/VGA, and never turn it on since we don't support it. */ 34179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_POWER_MANAGEMENT, 34279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes CH7017_DAC0_POWER_DOWN | 34379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes CH7017_DAC1_POWER_DOWN | 34479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes CH7017_DAC2_POWER_DOWN | 34579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes CH7017_DAC3_POWER_DOWN | 34679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes CH7017_TV_POWER_DOWN_EN); 34779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 34879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (mode == DRM_MODE_DPMS_ON) { 34979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes /* Turn on the LVDS */ 35079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, 35179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes val & ~CH7017_LVDS_POWER_DOWN_EN); 35279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } else { 35379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes /* Turn off the LVDS */ 35479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, 35579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes val | CH7017_LVDS_POWER_DOWN_EN); 35679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } 35779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 35879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes /* XXX: Should actually wait for update power status somehow */ 359a8ed0b16a924a59b56906e83d6c033a04a9818f6Chris Wilson msleep(20); 36079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 36179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 36279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic void ch7017_dump_regs(struct intel_dvo_device *dvo) 36379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 36479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes uint8_t val; 36579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 36679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes#define DUMP(reg) \ 36779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesdo { \ 36879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes ch7017_read(dvo, reg, &val); \ 369d0c3b04ae953fd3bf69f9b1430c22608d2d3b90dZhao Yakui DRM_DEBUG_KMS(#reg ": %02x\n", val); \ 37079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} while (0) 37179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 37279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); 37379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); 37479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); 37579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); 37679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_LVDS_PLL_VCO_CONTROL); 37779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); 37879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_LVDS_CONTROL_2); 37979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_OUTPUTS_ENABLE); 38079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes DUMP(CH7017_LVDS_POWER_DOWN); 38179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 38279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 38379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstatic void ch7017_destroy(struct intel_dvo_device *dvo) 38479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 38579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes struct ch7017_priv *priv = dvo->dev_priv; 38679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 38779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes if (priv) { 38879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes kfree(priv); 38979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes dvo->dev_priv = NULL; 39079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes } 39179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes} 39279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 39379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstruct intel_dvo_dev_ops ch7017_ops = { 39479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .init = ch7017_init, 39579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .detect = ch7017_detect, 39679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .mode_valid = ch7017_mode_valid, 39779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .mode_set = ch7017_mode_set, 39879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .dpms = ch7017_dpms, 39979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .dump_regs = ch7017_dump_regs, 40079e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes .destroy = ch7017_destroy, 40179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes}; 402