Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2009 Francisco Jerez.
0003  * All Rights Reserved.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining
0006  * a copy of this software and associated documentation files (the
0007  * "Software"), to deal in the Software without restriction, including
0008  * without limitation the rights to use, copy, modify, merge, publish,
0009  * distribute, sublicense, and/or sell copies of the Software, and to
0010  * permit persons to whom the Software is furnished to do so, subject to
0011  * the following conditions:
0012  *
0013  * The above copyright notice and this permission notice (including the
0014  * next paragraph) shall be included in all copies or substantial
0015  * portions of the Software.
0016  *
0017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0018  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0020  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
0021  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0022  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0023  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0024  *
0025  */
0026 
0027 #include <linux/module.h>
0028 
0029 #include "ch7006_priv.h"
0030 
0031 /* DRM encoder functions */
0032 
0033 static void ch7006_encoder_set_config(struct drm_encoder *encoder,
0034                       void *params)
0035 {
0036     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0037 
0038     priv->params = *(struct ch7006_encoder_params *)params;
0039 }
0040 
0041 static void ch7006_encoder_destroy(struct drm_encoder *encoder)
0042 {
0043     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0044 
0045     drm_property_destroy(encoder->dev, priv->scale_property);
0046 
0047     kfree(priv);
0048     to_encoder_slave(encoder)->slave_priv = NULL;
0049 
0050     drm_i2c_encoder_destroy(encoder);
0051 }
0052 
0053 static void  ch7006_encoder_dpms(struct drm_encoder *encoder, int mode)
0054 {
0055     struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
0056     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0057     struct ch7006_state *state = &priv->state;
0058 
0059     ch7006_dbg(client, "\n");
0060 
0061     if (mode == priv->last_dpms)
0062         return;
0063     priv->last_dpms = mode;
0064 
0065     ch7006_setup_power_state(encoder);
0066 
0067     ch7006_load_reg(client, state, CH7006_POWER);
0068 }
0069 
0070 static void ch7006_encoder_save(struct drm_encoder *encoder)
0071 {
0072     struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
0073     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0074 
0075     ch7006_dbg(client, "\n");
0076 
0077     ch7006_state_save(client, &priv->saved_state);
0078 }
0079 
0080 static void ch7006_encoder_restore(struct drm_encoder *encoder)
0081 {
0082     struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
0083     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0084 
0085     ch7006_dbg(client, "\n");
0086 
0087     ch7006_state_load(client, &priv->saved_state);
0088 }
0089 
0090 static bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder,
0091                       const struct drm_display_mode *mode,
0092                       struct drm_display_mode *adjusted_mode)
0093 {
0094     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0095 
0096     /* The ch7006 is painfully picky with the input timings so no
0097      * custom modes for now... */
0098 
0099     priv->mode = ch7006_lookup_mode(encoder, mode);
0100 
0101     return !!priv->mode;
0102 }
0103 
0104 static int ch7006_encoder_mode_valid(struct drm_encoder *encoder,
0105                      struct drm_display_mode *mode)
0106 {
0107     if (ch7006_lookup_mode(encoder, mode))
0108         return MODE_OK;
0109     else
0110         return MODE_BAD;
0111 }
0112 
0113 static void ch7006_encoder_mode_set(struct drm_encoder *encoder,
0114                      struct drm_display_mode *drm_mode,
0115                      struct drm_display_mode *adjusted_mode)
0116 {
0117     struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
0118     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0119     struct ch7006_encoder_params *params = &priv->params;
0120     struct ch7006_state *state = &priv->state;
0121     uint8_t *regs = state->regs;
0122     const struct ch7006_mode *mode = priv->mode;
0123     const struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
0124     int start_active;
0125 
0126     ch7006_dbg(client, "\n");
0127 
0128     regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode;
0129     regs[CH7006_BWIDTH] = 0;
0130     regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT,
0131                      params->input_format);
0132 
0133     regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK
0134         | bitf(CH7006_CLKMODE_XCM, params->xcm)
0135         | bitf(CH7006_CLKMODE_PCM, params->pcm);
0136     if (params->clock_mode)
0137         regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER;
0138     if (params->clock_edge)
0139         regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE;
0140 
0141     start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7);
0142     regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active);
0143     regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active);
0144 
0145     regs[CH7006_INPUT_SYNC] = 0;
0146     if (params->sync_direction)
0147         regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT;
0148     if (params->sync_encoding)
0149         regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED;
0150     if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC)
0151         regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC;
0152     if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC)
0153         regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC;
0154 
0155     regs[CH7006_DETECT] = 0;
0156     regs[CH7006_BCLKOUT] = 0;
0157 
0158     regs[CH7006_SUBC_INC3] = 0;
0159     if (params->pout_level)
0160         regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V;
0161 
0162     regs[CH7006_SUBC_INC4] = 0;
0163     if (params->active_detect)
0164         regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT;
0165 
0166     regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL];
0167 
0168     ch7006_setup_levels(encoder);
0169     ch7006_setup_subcarrier(encoder);
0170     ch7006_setup_pll(encoder);
0171     ch7006_setup_power_state(encoder);
0172     ch7006_setup_properties(encoder);
0173 
0174     ch7006_state_load(client, state);
0175 }
0176 
0177 static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder,
0178                                struct drm_connector *connector)
0179 {
0180     struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
0181     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0182     struct ch7006_state *state = &priv->state;
0183     int det;
0184 
0185     ch7006_dbg(client, "\n");
0186 
0187     ch7006_save_reg(client, state, CH7006_DETECT);
0188     ch7006_save_reg(client, state, CH7006_POWER);
0189     ch7006_save_reg(client, state, CH7006_CLKMODE);
0190 
0191     ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET |
0192                        bitfs(CH7006_POWER_LEVEL, NORMAL));
0193     ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER);
0194 
0195     ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE);
0196 
0197     ch7006_write(client, CH7006_DETECT, 0);
0198 
0199     det = ch7006_read(client, CH7006_DETECT);
0200 
0201     ch7006_load_reg(client, state, CH7006_CLKMODE);
0202     ch7006_load_reg(client, state, CH7006_POWER);
0203     ch7006_load_reg(client, state, CH7006_DETECT);
0204 
0205     if ((det & (CH7006_DETECT_SVIDEO_Y_TEST|
0206             CH7006_DETECT_SVIDEO_C_TEST|
0207             CH7006_DETECT_CVBS_TEST)) == 0)
0208         priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART;
0209     else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST|
0210              CH7006_DETECT_SVIDEO_C_TEST)) == 0)
0211         priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO;
0212     else if ((det & CH7006_DETECT_CVBS_TEST) == 0)
0213         priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite;
0214     else
0215         priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
0216 
0217     drm_object_property_set_value(&connector->base,
0218             encoder->dev->mode_config.tv_subconnector_property,
0219                             priv->subconnector);
0220 
0221     return priv->subconnector ? connector_status_connected :
0222                     connector_status_disconnected;
0223 }
0224 
0225 static int ch7006_encoder_get_modes(struct drm_encoder *encoder,
0226                     struct drm_connector *connector)
0227 {
0228     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0229     const struct ch7006_mode *mode;
0230     int n = 0;
0231 
0232     for (mode = ch7006_modes; mode->mode.clock; mode++) {
0233         if (~mode->valid_scales & 1<<priv->scale ||
0234             ~mode->valid_norms & 1<<priv->norm)
0235             continue;
0236 
0237         drm_mode_probed_add(connector,
0238                 drm_mode_duplicate(encoder->dev, &mode->mode));
0239 
0240         n++;
0241     }
0242 
0243     return n;
0244 }
0245 
0246 static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
0247                        struct drm_connector *connector)
0248 {
0249     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0250     struct drm_device *dev = encoder->dev;
0251     struct drm_mode_config *conf = &dev->mode_config;
0252 
0253     drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
0254 
0255     priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
0256     if (!priv->scale_property)
0257         return -ENOMEM;
0258 
0259     drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property,
0260                       priv->select_subconnector);
0261     drm_object_attach_property(&connector->base, conf->tv_subconnector_property,
0262                       priv->subconnector);
0263     drm_object_attach_property(&connector->base, conf->tv_left_margin_property,
0264                       priv->hmargin);
0265     drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property,
0266                       priv->vmargin);
0267     drm_object_attach_property(&connector->base, conf->tv_mode_property,
0268                       priv->norm);
0269     drm_object_attach_property(&connector->base, conf->tv_brightness_property,
0270                       priv->brightness);
0271     drm_object_attach_property(&connector->base, conf->tv_contrast_property,
0272                       priv->contrast);
0273     drm_object_attach_property(&connector->base, conf->tv_flicker_reduction_property,
0274                       priv->flicker);
0275     drm_object_attach_property(&connector->base, priv->scale_property,
0276                       priv->scale);
0277 
0278     return 0;
0279 }
0280 
0281 static int ch7006_encoder_set_property(struct drm_encoder *encoder,
0282                        struct drm_connector *connector,
0283                        struct drm_property *property,
0284                        uint64_t val)
0285 {
0286     struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
0287     struct ch7006_priv *priv = to_ch7006_priv(encoder);
0288     struct ch7006_state *state = &priv->state;
0289     struct drm_mode_config *conf = &encoder->dev->mode_config;
0290     struct drm_crtc *crtc = encoder->crtc;
0291     bool modes_changed = false;
0292 
0293     ch7006_dbg(client, "\n");
0294 
0295     if (property == conf->tv_select_subconnector_property) {
0296         priv->select_subconnector = val;
0297 
0298         ch7006_setup_power_state(encoder);
0299 
0300         ch7006_load_reg(client, state, CH7006_POWER);
0301 
0302     } else if (property == conf->tv_left_margin_property) {
0303         priv->hmargin = val;
0304 
0305         ch7006_setup_properties(encoder);
0306 
0307         ch7006_load_reg(client, state, CH7006_POV);
0308         ch7006_load_reg(client, state, CH7006_HPOS);
0309 
0310     } else if (property == conf->tv_bottom_margin_property) {
0311         priv->vmargin = val;
0312 
0313         ch7006_setup_properties(encoder);
0314 
0315         ch7006_load_reg(client, state, CH7006_POV);
0316         ch7006_load_reg(client, state, CH7006_VPOS);
0317 
0318     } else if (property == conf->tv_mode_property) {
0319         if (connector->dpms != DRM_MODE_DPMS_OFF)
0320             return -EINVAL;
0321 
0322         priv->norm = val;
0323 
0324         modes_changed = true;
0325 
0326     } else if (property == conf->tv_brightness_property) {
0327         priv->brightness = val;
0328 
0329         ch7006_setup_levels(encoder);
0330 
0331         ch7006_load_reg(client, state, CH7006_BLACK_LEVEL);
0332 
0333     } else if (property == conf->tv_contrast_property) {
0334         priv->contrast = val;
0335 
0336         ch7006_setup_properties(encoder);
0337 
0338         ch7006_load_reg(client, state, CH7006_CONTRAST);
0339 
0340     } else if (property == conf->tv_flicker_reduction_property) {
0341         priv->flicker = val;
0342 
0343         ch7006_setup_properties(encoder);
0344 
0345         ch7006_load_reg(client, state, CH7006_FFILTER);
0346 
0347     } else if (property == priv->scale_property) {
0348         if (connector->dpms != DRM_MODE_DPMS_OFF)
0349             return -EINVAL;
0350 
0351         priv->scale = val;
0352 
0353         modes_changed = true;
0354 
0355     } else {
0356         return -EINVAL;
0357     }
0358 
0359     if (modes_changed) {
0360         drm_helper_probe_single_connector_modes(connector, 0, 0);
0361 
0362         if (crtc)
0363             drm_crtc_helper_set_mode(crtc, &crtc->mode,
0364                          crtc->x, crtc->y,
0365                          crtc->primary->fb);
0366     }
0367 
0368     return 0;
0369 }
0370 
0371 static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
0372     .set_config = ch7006_encoder_set_config,
0373     .destroy = ch7006_encoder_destroy,
0374     .dpms = ch7006_encoder_dpms,
0375     .save = ch7006_encoder_save,
0376     .restore = ch7006_encoder_restore,
0377     .mode_fixup = ch7006_encoder_mode_fixup,
0378     .mode_valid = ch7006_encoder_mode_valid,
0379     .mode_set = ch7006_encoder_mode_set,
0380     .detect = ch7006_encoder_detect,
0381     .get_modes = ch7006_encoder_get_modes,
0382     .create_resources = ch7006_encoder_create_resources,
0383     .set_property = ch7006_encoder_set_property,
0384 };
0385 
0386 
0387 /* I2C driver functions */
0388 
0389 static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
0390 {
0391     uint8_t addr = CH7006_VERSION_ID;
0392     uint8_t val;
0393     int ret;
0394 
0395     ch7006_dbg(client, "\n");
0396 
0397     ret = i2c_master_send(client, &addr, sizeof(addr));
0398     if (ret < 0)
0399         goto fail;
0400 
0401     ret = i2c_master_recv(client, &val, sizeof(val));
0402     if (ret < 0)
0403         goto fail;
0404 
0405     ch7006_info(client, "Detected version ID: %x\n", val);
0406 
0407     /* I don't know what this is for, but otherwise I get no
0408      * signal.
0409      */
0410     ch7006_write(client, 0x3d, 0x0);
0411 
0412     return 0;
0413 
0414 fail:
0415     ch7006_err(client, "Error %d reading version ID\n", ret);
0416 
0417     return -ENODEV;
0418 }
0419 
0420 static int ch7006_remove(struct i2c_client *client)
0421 {
0422     ch7006_dbg(client, "\n");
0423 
0424     return 0;
0425 }
0426 
0427 static int ch7006_resume(struct device *dev)
0428 {
0429     struct i2c_client *client = to_i2c_client(dev);
0430 
0431     ch7006_dbg(client, "\n");
0432 
0433     ch7006_write(client, 0x3d, 0x0);
0434 
0435     return 0;
0436 }
0437 
0438 static int ch7006_encoder_init(struct i2c_client *client,
0439                    struct drm_device *dev,
0440                    struct drm_encoder_slave *encoder)
0441 {
0442     struct ch7006_priv *priv;
0443     int i;
0444 
0445     ch7006_dbg(client, "\n");
0446 
0447     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0448     if (!priv)
0449         return -ENOMEM;
0450 
0451     encoder->slave_priv = priv;
0452     encoder->slave_funcs = &ch7006_encoder_funcs;
0453 
0454     priv->norm = TV_NORM_PAL;
0455     priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic;
0456     priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
0457     priv->scale = 1;
0458     priv->contrast = 50;
0459     priv->brightness = 50;
0460     priv->flicker = 50;
0461     priv->hmargin = 50;
0462     priv->vmargin = 50;
0463     priv->last_dpms = -1;
0464     priv->chip_version = ch7006_read(client, CH7006_VERSION_ID);
0465 
0466     if (ch7006_tv_norm) {
0467         for (i = 0; i < NUM_TV_NORMS; i++) {
0468             if (!strcmp(ch7006_tv_norm_names[i], ch7006_tv_norm)) {
0469                 priv->norm = i;
0470                 break;
0471             }
0472         }
0473 
0474         if (i == NUM_TV_NORMS)
0475             ch7006_err(client, "Invalid TV norm setting \"%s\".\n",
0476                    ch7006_tv_norm);
0477     }
0478 
0479     if (ch7006_scale >= 0 && ch7006_scale <= 2)
0480         priv->scale = ch7006_scale;
0481     else
0482         ch7006_err(client, "Invalid scale setting \"%d\".\n",
0483                ch7006_scale);
0484 
0485     return 0;
0486 }
0487 
0488 static const struct i2c_device_id ch7006_ids[] = {
0489     { "ch7006", 0 },
0490     { }
0491 };
0492 MODULE_DEVICE_TABLE(i2c, ch7006_ids);
0493 
0494 static const struct dev_pm_ops ch7006_pm_ops = {
0495     .resume = ch7006_resume,
0496 };
0497 
0498 static struct drm_i2c_encoder_driver ch7006_driver = {
0499     .i2c_driver = {
0500         .probe = ch7006_probe,
0501         .remove = ch7006_remove,
0502 
0503         .driver = {
0504             .name = "ch7006",
0505             .pm = &ch7006_pm_ops,
0506         },
0507 
0508         .id_table = ch7006_ids,
0509     },
0510 
0511     .encoder_init = ch7006_encoder_init,
0512 };
0513 
0514 
0515 /* Module initialization */
0516 
0517 static int __init ch7006_init(void)
0518 {
0519     return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver);
0520 }
0521 
0522 static void __exit ch7006_exit(void)
0523 {
0524     drm_i2c_encoder_unregister(&ch7006_driver);
0525 }
0526 
0527 int ch7006_debug;
0528 module_param_named(debug, ch7006_debug, int, 0600);
0529 MODULE_PARM_DESC(debug, "Enable debug output.");
0530 
0531 char *ch7006_tv_norm;
0532 module_param_named(tv_norm, ch7006_tv_norm, charp, 0600);
0533 MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
0534          "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n"
0535          "\t\tDefault: PAL");
0536 
0537 int ch7006_scale = 1;
0538 module_param_named(scale, ch7006_scale, int, 0600);
0539 MODULE_PARM_DESC(scale, "Default scale.\n"
0540          "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n"
0541          "\t\t\t1 -> Select default video modes.\n"
0542          "\t\t\t2 -> Select video modes with a lower blanking ratio.");
0543 
0544 MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
0545 MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver");
0546 MODULE_LICENSE("GPL and additional rights");
0547 
0548 module_init(ch7006_init);
0549 module_exit(ch7006_exit);