linux/drivers/media/i2c/ths7303.c
<<
>>
Prefs
   1/*
   2 * ths7303/53- THS7303/53 Video Amplifier driver
   3 *
   4 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
   5 * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
   6 *
   7 * Author: Chaithrika U S <chaithrika@ti.com>
   8 *
   9 * Contributors:
  10 *     Hans Verkuil <hans.verkuil@cisco.com>
  11 *     Lad, Prabhakar <prabhakar.lad@ti.com>
  12 *     Martin Bugge <marbugge@cisco.com>
  13 *
  14 * This program is free software; you can redistribute it and/or
  15 * modify it under the terms of the GNU General Public License as
  16 * published by the Free Software Foundation version 2.
  17 *
  18 * This program is distributed .as is. WITHOUT ANY WARRANTY of any
  19 * kind, whether express or implied; without even the implied warranty
  20 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 */
  23
  24#include <linux/i2c.h>
  25#include <linux/module.h>
  26#include <linux/slab.h>
  27
  28#include <media/i2c/ths7303.h>
  29#include <media/v4l2-device.h>
  30
  31#define THS7303_CHANNEL_1       1
  32#define THS7303_CHANNEL_2       2
  33#define THS7303_CHANNEL_3       3
  34
  35struct ths7303_state {
  36        struct v4l2_subdev              sd;
  37        const struct ths7303_platform_data *pdata;
  38        struct v4l2_bt_timings          bt;
  39        int std_id;
  40        int stream_on;
  41};
  42
  43enum ths7303_filter_mode {
  44        THS7303_FILTER_MODE_480I_576I,
  45        THS7303_FILTER_MODE_480P_576P,
  46        THS7303_FILTER_MODE_720P_1080I,
  47        THS7303_FILTER_MODE_1080P,
  48        THS7303_FILTER_MODE_DISABLE
  49};
  50
  51MODULE_DESCRIPTION("TI THS7303 video amplifier driver");
  52MODULE_AUTHOR("Chaithrika U S");
  53MODULE_LICENSE("GPL");
  54
  55static inline struct ths7303_state *to_state(struct v4l2_subdev *sd)
  56{
  57        return container_of(sd, struct ths7303_state, sd);
  58}
  59
  60static int ths7303_read(struct v4l2_subdev *sd, u8 reg)
  61{
  62        struct i2c_client *client = v4l2_get_subdevdata(sd);
  63
  64        return i2c_smbus_read_byte_data(client, reg);
  65}
  66
  67static int ths7303_write(struct v4l2_subdev *sd, u8 reg, u8 val)
  68{
  69        struct i2c_client *client = v4l2_get_subdevdata(sd);
  70        int ret;
  71        int i;
  72
  73        for (i = 0; i < 3; i++) {
  74                ret = i2c_smbus_write_byte_data(client, reg, val);
  75                if (ret == 0)
  76                        return 0;
  77        }
  78        return ret;
  79}
  80
  81/* following function is used to set ths7303 */
  82static int ths7303_setval(struct v4l2_subdev *sd,
  83                          enum ths7303_filter_mode mode)
  84{
  85        struct i2c_client *client = v4l2_get_subdevdata(sd);
  86        struct ths7303_state *state = to_state(sd);
  87        const struct ths7303_platform_data *pdata = state->pdata;
  88        u8 val, sel = 0;
  89        int err, disable = 0;
  90
  91        if (!client)
  92                return -EINVAL;
  93
  94        switch (mode) {
  95        case THS7303_FILTER_MODE_1080P:
  96                sel = 0x3;      /*1080p and SXGA/UXGA */
  97                break;
  98        case THS7303_FILTER_MODE_720P_1080I:
  99                sel = 0x2;      /*720p, 1080i and SVGA/XGA */
 100                break;
 101        case THS7303_FILTER_MODE_480P_576P:
 102                sel = 0x1;      /* EDTV 480p/576p and VGA */
 103                break;
 104        case THS7303_FILTER_MODE_480I_576I:
 105                sel = 0x0;      /* SDTV, S-Video, 480i/576i */
 106                break;
 107        default:
 108                /* disable all channels */
 109                disable = 1;
 110        }
 111
 112        val = (sel << 6) | (sel << 3);
 113        if (!disable)
 114                val |= (pdata->ch_1 & 0x27);
 115        err = ths7303_write(sd, THS7303_CHANNEL_1, val);
 116        if (err)
 117                goto out;
 118
 119        val = (sel << 6) | (sel << 3);
 120        if (!disable)
 121                val |= (pdata->ch_2 & 0x27);
 122        err = ths7303_write(sd, THS7303_CHANNEL_2, val);
 123        if (err)
 124                goto out;
 125
 126        val = (sel << 6) | (sel << 3);
 127        if (!disable)
 128                val |= (pdata->ch_3 & 0x27);
 129        err = ths7303_write(sd, THS7303_CHANNEL_3, val);
 130        if (err)
 131                goto out;
 132
 133        return 0;
 134out:
 135        pr_info("write byte data failed\n");
 136        return err;
 137}
 138
 139static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
 140{
 141        struct ths7303_state *state = to_state(sd);
 142
 143        if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
 144                state->std_id = 1;
 145                state->bt.pixelclock = 0;
 146                return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
 147        }
 148
 149        return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
 150}
 151
 152static int ths7303_config(struct v4l2_subdev *sd)
 153{
 154        struct ths7303_state *state = to_state(sd);
 155        int res;
 156
 157        if (!state->stream_on) {
 158                ths7303_write(sd, THS7303_CHANNEL_1,
 159                              (ths7303_read(sd, THS7303_CHANNEL_1) & 0xf8) |
 160                              0x00);
 161                ths7303_write(sd, THS7303_CHANNEL_2,
 162                              (ths7303_read(sd, THS7303_CHANNEL_2) & 0xf8) |
 163                              0x00);
 164                ths7303_write(sd, THS7303_CHANNEL_3,
 165                              (ths7303_read(sd, THS7303_CHANNEL_3) & 0xf8) |
 166                              0x00);
 167                return 0;
 168        }
 169
 170        if (state->bt.pixelclock > 120000000)
 171                res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P);
 172        else if (state->bt.pixelclock > 70000000)
 173                res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I);
 174        else if (state->bt.pixelclock > 20000000)
 175                res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P);
 176        else if (state->std_id)
 177                res = ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
 178        else
 179                /* disable all channels */
 180                res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
 181
 182        return res;
 183
 184}
 185
 186static int ths7303_s_stream(struct v4l2_subdev *sd, int enable)
 187{
 188        struct ths7303_state *state = to_state(sd);
 189
 190        state->stream_on = enable;
 191
 192        return ths7303_config(sd);
 193}
 194
 195/* for setting filter for HD output */
 196static int ths7303_s_dv_timings(struct v4l2_subdev *sd,
 197                               struct v4l2_dv_timings *dv_timings)
 198{
 199        struct ths7303_state *state = to_state(sd);
 200
 201        if (!dv_timings || dv_timings->type != V4L2_DV_BT_656_1120)
 202                return -EINVAL;
 203
 204        state->bt = dv_timings->bt;
 205        state->std_id = 0;
 206
 207        return ths7303_config(sd);
 208}
 209
 210static const struct v4l2_subdev_video_ops ths7303_video_ops = {
 211        .s_stream       = ths7303_s_stream,
 212        .s_std_output   = ths7303_s_std_output,
 213        .s_dv_timings   = ths7303_s_dv_timings,
 214};
 215
 216#ifdef CONFIG_VIDEO_ADV_DEBUG
 217
 218static int ths7303_g_register(struct v4l2_subdev *sd,
 219                              struct v4l2_dbg_register *reg)
 220{
 221        reg->size = 1;
 222        reg->val = ths7303_read(sd, reg->reg);
 223        return 0;
 224}
 225
 226static int ths7303_s_register(struct v4l2_subdev *sd,
 227                              const struct v4l2_dbg_register *reg)
 228{
 229        ths7303_write(sd, reg->reg, reg->val);
 230        return 0;
 231}
 232#endif
 233
 234static const char * const stc_lpf_sel_txt[4] = {
 235        "500-kHz Filter",
 236        "2.5-MHz Filter",
 237        "5-MHz Filter",
 238        "5-MHz Filter",
 239};
 240
 241static const char * const in_mux_sel_txt[2] = {
 242        "Input A Select",
 243        "Input B Select",
 244};
 245
 246static const char * const lpf_freq_sel_txt[4] = {
 247        "9-MHz LPF",
 248        "16-MHz LPF",
 249        "35-MHz LPF",
 250        "Bypass LPF",
 251};
 252
 253static const char * const in_bias_sel_dis_cont_txt[8] = {
 254        "Disable Channel",
 255        "Mute Function - No Output",
 256        "DC Bias Select",
 257        "DC Bias + 250 mV Offset Select",
 258        "AC Bias Select",
 259        "Sync Tip Clamp with low bias",
 260        "Sync Tip Clamp with mid bias",
 261        "Sync Tip Clamp with high bias",
 262};
 263
 264static void ths7303_log_channel_status(struct v4l2_subdev *sd, u8 reg)
 265{
 266        u8 val = ths7303_read(sd, reg);
 267
 268        if ((val & 0x7) == 0) {
 269                v4l2_info(sd, "Channel %d Off\n", reg);
 270                return;
 271        }
 272
 273        v4l2_info(sd, "Channel %d On\n", reg);
 274        v4l2_info(sd, "  value 0x%x\n", val);
 275        v4l2_info(sd, "  %s\n", stc_lpf_sel_txt[(val >> 6) & 0x3]);
 276        v4l2_info(sd, "  %s\n", in_mux_sel_txt[(val >> 5) & 0x1]);
 277        v4l2_info(sd, "  %s\n", lpf_freq_sel_txt[(val >> 3) & 0x3]);
 278        v4l2_info(sd, "  %s\n", in_bias_sel_dis_cont_txt[(val >> 0) & 0x7]);
 279}
 280
 281static int ths7303_log_status(struct v4l2_subdev *sd)
 282{
 283        struct ths7303_state *state = to_state(sd);
 284
 285        v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off");
 286
 287        if (state->bt.pixelclock) {
 288                struct v4l2_bt_timings *bt = &state->bt;
 289                u32 frame_width, frame_height;
 290
 291                frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
 292                frame_height = V4L2_DV_BT_FRAME_HEIGHT(bt);
 293                v4l2_info(sd,
 294                          "timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n",
 295                          bt->width, bt->height, bt->interlaced ? "i" : "p",
 296                          (frame_height * frame_width) > 0 ?
 297                          (int)bt->pixelclock /
 298                          (frame_height * frame_width) : 0,
 299                          frame_width, frame_height,
 300                          (int)bt->pixelclock, bt->polarities);
 301        } else {
 302                v4l2_info(sd, "no timings set\n");
 303        }
 304
 305        ths7303_log_channel_status(sd, THS7303_CHANNEL_1);
 306        ths7303_log_channel_status(sd, THS7303_CHANNEL_2);
 307        ths7303_log_channel_status(sd, THS7303_CHANNEL_3);
 308
 309        return 0;
 310}
 311
 312static const struct v4l2_subdev_core_ops ths7303_core_ops = {
 313        .log_status = ths7303_log_status,
 314#ifdef CONFIG_VIDEO_ADV_DEBUG
 315        .g_register = ths7303_g_register,
 316        .s_register = ths7303_s_register,
 317#endif
 318};
 319
 320static const struct v4l2_subdev_ops ths7303_ops = {
 321        .core   = &ths7303_core_ops,
 322        .video  = &ths7303_video_ops,
 323};
 324
 325static int ths7303_probe(struct i2c_client *client,
 326                        const struct i2c_device_id *id)
 327{
 328        struct ths7303_platform_data *pdata = client->dev.platform_data;
 329        struct ths7303_state *state;
 330        struct v4l2_subdev *sd;
 331
 332        if (pdata == NULL) {
 333                dev_err(&client->dev, "No platform data\n");
 334                return -EINVAL;
 335        }
 336
 337        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 338                return -ENODEV;
 339
 340        v4l_info(client, "chip found @ 0x%x (%s)\n",
 341                        client->addr << 1, client->adapter->name);
 342
 343        state = devm_kzalloc(&client->dev, sizeof(struct ths7303_state),
 344                             GFP_KERNEL);
 345        if (!state)
 346                return -ENOMEM;
 347
 348        state->pdata = pdata;
 349        sd = &state->sd;
 350        v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
 351
 352        /* set to default 480I_576I filter mode */
 353        if (ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I) < 0) {
 354                v4l_err(client, "Setting to 480I_576I filter mode failed!\n");
 355                return -EINVAL;
 356        }
 357
 358        return 0;
 359}
 360
 361static int ths7303_remove(struct i2c_client *client)
 362{
 363        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 364
 365        v4l2_device_unregister_subdev(sd);
 366
 367        return 0;
 368}
 369
 370static const struct i2c_device_id ths7303_id[] = {
 371        {"ths7303", 0},
 372        {"ths7353", 0},
 373        {},
 374};
 375
 376MODULE_DEVICE_TABLE(i2c, ths7303_id);
 377
 378static struct i2c_driver ths7303_driver = {
 379        .driver = {
 380                .name   = "ths73x3",
 381        },
 382        .probe          = ths7303_probe,
 383        .remove         = ths7303_remove,
 384        .id_table       = ths7303_id,
 385};
 386
 387module_i2c_driver(ths7303_driver);
 388