linux/drivers/media/i2c/sony-btf-mpx.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-2006 Micronas USA Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License (Version 2) as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/init.h>
  16#include <linux/i2c.h>
  17#include <linux/videodev2.h>
  18#include <media/tuner.h>
  19#include <media/v4l2-common.h>
  20#include <media/v4l2-ioctl.h>
  21#include <media/v4l2-device.h>
  22#include <linux/slab.h>
  23
  24MODULE_DESCRIPTION("sony-btf-mpx driver");
  25MODULE_LICENSE("GPL v2");
  26
  27static int debug;
  28module_param(debug, int, 0644);
  29MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on");
  30
  31/* #define MPX_DEBUG */
  32
  33/*
  34 * Note:
  35 *
  36 * AS(IF/MPX) pin:      LOW      HIGH/OPEN
  37 * IF/MPX address:   0x42/0x40   0x43/0x44
  38 */
  39
  40
  41static int force_mpx_mode = -1;
  42module_param(force_mpx_mode, int, 0644);
  43
  44struct sony_btf_mpx {
  45        struct v4l2_subdev sd;
  46        int mpxmode;
  47        u32 audmode;
  48};
  49
  50static inline struct sony_btf_mpx *to_state(struct v4l2_subdev *sd)
  51{
  52        return container_of(sd, struct sony_btf_mpx, sd);
  53}
  54
  55static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
  56{
  57        u8 buffer[5];
  58        struct i2c_msg msg;
  59
  60        buffer[0] = dev;
  61        buffer[1] = addr >> 8;
  62        buffer[2] = addr & 0xff;
  63        buffer[3] = val >> 8;
  64        buffer[4] = val & 0xff;
  65        msg.addr = client->addr;
  66        msg.flags = 0;
  67        msg.len = 5;
  68        msg.buf = buffer;
  69        i2c_transfer(client->adapter, &msg, 1);
  70        return 0;
  71}
  72
  73/*
  74 * MPX register values for the BTF-PG472Z:
  75 *
  76 *                                 FM_     NICAM_  SCART_
  77 *          MODUS  SOURCE    ACB   PRESCAL PRESCAL PRESCAL SYSTEM  VOLUME
  78 *         10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
  79 *         ---------------------------------------------------------------
  80 * Auto     1003    0020    0100    2603    5000    XXXX    0001    7500
  81 *
  82 * B/G
  83 *  Mono    1003    0020    0100    2603    5000    XXXX    0003    7500
  84 *  A2      1003    0020    0100    2601    5000    XXXX    0003    7500
  85 *  NICAM   1003    0120    0100    2603    5000    XXXX    0008    7500
  86 *
  87 * I
  88 *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
  89 *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
  90 *
  91 * D/K
  92 *  Mono    1003    0020    0100    2603    5000    XXXX    0004    7500
  93 *  A2-1    1003    0020    0100    2601    5000    XXXX    0004    7500
  94 *  A2-2    1003    0020    0100    2601    5000    XXXX    0005    7500
  95 *  A2-3    1003    0020    0100    2601    5000    XXXX    0007    7500
  96 *  NICAM   1003    0120    0100    2603    5000    XXXX    000B    7500
  97 *
  98 * L/L'
  99 *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
 100 *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
 101 *
 102 * M
 103 *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
 104 *
 105 * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
 106 *
 107 * Bilingual selection in A2/NICAM:
 108 *
 109 *         High byte of SOURCE     Left chan   Right chan
 110 *                 0x01              MAIN         SUB
 111 *                 0x03              MAIN         MAIN
 112 *                 0x04              SUB          SUB
 113 *
 114 * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
 115 * 0x00 (all other bands).  Force mono in A2 with FMONO_A2:
 116 *
 117 *                      FMONO_A2
 118 *                      10/0022
 119 *                      --------
 120 *     Forced mono ON     07F0
 121 *     Forced mono OFF    0190
 122 */
 123
 124static const struct {
 125        enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
 126        u16 modus;
 127        u16 source;
 128        u16 acb;
 129        u16 fm_prescale;
 130        u16 nicam_prescale;
 131        u16 scart_prescale;
 132        u16 system;
 133        u16 volume;
 134} mpx_audio_modes[] = {
 135        /* Auto */      { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 136                                        0x5000, 0x0000, 0x0001, 0x7500 },
 137        /* B/G Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 138                                        0x5000, 0x0000, 0x0003, 0x7500 },
 139        /* B/G A2 */    { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 140                                        0x5000, 0x0000, 0x0003, 0x7500 },
 141        /* B/G NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
 142                                        0x5000, 0x0000, 0x0008, 0x7500 },
 143        /* I Mono */    { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 144                                        0x7900, 0x0000, 0x000A, 0x7500 },
 145        /* I NICAM */   { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
 146                                        0x7900, 0x0000, 0x000A, 0x7500 },
 147        /* D/K Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 148                                        0x5000, 0x0000, 0x0004, 0x7500 },
 149        /* D/K A2-1 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 150                                        0x5000, 0x0000, 0x0004, 0x7500 },
 151        /* D/K A2-2 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 152                                        0x5000, 0x0000, 0x0005, 0x7500 },
 153        /* D/K A2-3 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 154                                        0x5000, 0x0000, 0x0007, 0x7500 },
 155        /* D/K NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
 156                                        0x5000, 0x0000, 0x000B, 0x7500 },
 157        /* L/L' Mono */ { AUD_MONO,     0x0003, 0x0200, 0x0100, 0x7C03,
 158                                        0x5000, 0x2200, 0x0009, 0x7500 },
 159        /* L/L' NICAM */{ AUD_NICAM_L,  0x0003, 0x0120, 0x0100, 0x7C03,
 160                                        0x5000, 0x0000, 0x0009, 0x7500 },
 161};
 162
 163#define MPX_NUM_MODES   ARRAY_SIZE(mpx_audio_modes)
 164
 165static int mpx_setup(struct sony_btf_mpx *t)
 166{
 167        struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
 168        u16 source = 0;
 169        u8 buffer[3];
 170        struct i2c_msg msg;
 171        int mode = t->mpxmode;
 172
 173        /* reset MPX */
 174        buffer[0] = 0x00;
 175        buffer[1] = 0x80;
 176        buffer[2] = 0x00;
 177        msg.addr = client->addr;
 178        msg.flags = 0;
 179        msg.len = 3;
 180        msg.buf = buffer;
 181        i2c_transfer(client->adapter, &msg, 1);
 182        buffer[1] = 0x00;
 183        i2c_transfer(client->adapter, &msg, 1);
 184
 185        if (t->audmode != V4L2_TUNER_MODE_MONO)
 186                mode++;
 187
 188        if (mpx_audio_modes[mode].audio_mode != AUD_MONO) {
 189                switch (t->audmode) {
 190                case V4L2_TUNER_MODE_MONO:
 191                        switch (mpx_audio_modes[mode].audio_mode) {
 192                        case AUD_A2:
 193                                source = mpx_audio_modes[mode].source;
 194                                break;
 195                        case AUD_NICAM:
 196                                source = 0x0000;
 197                                break;
 198                        case AUD_NICAM_L:
 199                                source = 0x0200;
 200                                break;
 201                        default:
 202                                break;
 203                        }
 204                        break;
 205                case V4L2_TUNER_MODE_STEREO:
 206                        source = mpx_audio_modes[mode].source;
 207                        break;
 208                case V4L2_TUNER_MODE_LANG1:
 209                        source = 0x0300;
 210                        break;
 211                case V4L2_TUNER_MODE_LANG2:
 212                        source = 0x0400;
 213                        break;
 214                }
 215                source |= mpx_audio_modes[mode].source & 0x00ff;
 216        } else
 217                source = mpx_audio_modes[mode].source;
 218
 219        mpx_write(client, 0x10, 0x0030, mpx_audio_modes[mode].modus);
 220        mpx_write(client, 0x12, 0x0008, source);
 221        mpx_write(client, 0x12, 0x0013, mpx_audio_modes[mode].acb);
 222        mpx_write(client, 0x12, 0x000e,
 223                        mpx_audio_modes[mode].fm_prescale);
 224        mpx_write(client, 0x12, 0x0010,
 225                        mpx_audio_modes[mode].nicam_prescale);
 226        mpx_write(client, 0x12, 0x000d,
 227                        mpx_audio_modes[mode].scart_prescale);
 228        mpx_write(client, 0x10, 0x0020, mpx_audio_modes[mode].system);
 229        mpx_write(client, 0x12, 0x0000, mpx_audio_modes[mode].volume);
 230        if (mpx_audio_modes[mode].audio_mode == AUD_A2)
 231                mpx_write(client, 0x10, 0x0022,
 232                        t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
 233
 234#ifdef MPX_DEBUG
 235        {
 236                u8 buf1[3], buf2[2];
 237                struct i2c_msg msgs[2];
 238
 239                v4l2_info(client,
 240                        "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n",
 241                        mpx_audio_modes[mode].modus,
 242                        source,
 243                        mpx_audio_modes[mode].acb,
 244                        mpx_audio_modes[mode].fm_prescale,
 245                        mpx_audio_modes[mode].nicam_prescale,
 246                        mpx_audio_modes[mode].scart_prescale,
 247                        mpx_audio_modes[mode].system,
 248                        mpx_audio_modes[mode].volume);
 249                buf1[0] = 0x11;
 250                buf1[1] = 0x00;
 251                buf1[2] = 0x7e;
 252                msgs[0].addr = client->addr;
 253                msgs[0].flags = 0;
 254                msgs[0].len = 3;
 255                msgs[0].buf = buf1;
 256                msgs[1].addr = client->addr;
 257                msgs[1].flags = I2C_M_RD;
 258                msgs[1].len = 2;
 259                msgs[1].buf = buf2;
 260                i2c_transfer(client->adapter, msgs, 2);
 261                v4l2_info(client, "MPX system: %02x%02x\n",
 262                                buf2[0], buf2[1]);
 263                buf1[0] = 0x11;
 264                buf1[1] = 0x02;
 265                buf1[2] = 0x00;
 266                i2c_transfer(client->adapter, msgs, 2);
 267                v4l2_info(client, "MPX status: %02x%02x\n",
 268                                buf2[0], buf2[1]);
 269        }
 270#endif
 271        return 0;
 272}
 273
 274
 275static int sony_btf_mpx_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 276{
 277        struct sony_btf_mpx *t = to_state(sd);
 278        int default_mpx_mode = 0;
 279
 280        if (std & V4L2_STD_PAL_BG)
 281                default_mpx_mode = 1;
 282        else if (std & V4L2_STD_PAL_I)
 283                default_mpx_mode = 4;
 284        else if (std & V4L2_STD_PAL_DK)
 285                default_mpx_mode = 6;
 286        else if (std & V4L2_STD_SECAM_L)
 287                default_mpx_mode = 11;
 288
 289        if (default_mpx_mode != t->mpxmode) {
 290                t->mpxmode = default_mpx_mode;
 291                mpx_setup(t);
 292        }
 293        return 0;
 294}
 295
 296static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 297{
 298        struct sony_btf_mpx *t = to_state(sd);
 299
 300        vt->capability = V4L2_TUNER_CAP_NORM |
 301                V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
 302                V4L2_TUNER_CAP_LANG2;
 303        vt->rxsubchans = V4L2_TUNER_SUB_MONO |
 304                V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
 305                V4L2_TUNER_SUB_LANG2;
 306        vt->audmode = t->audmode;
 307        return 0;
 308}
 309
 310static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
 311{
 312        struct sony_btf_mpx *t = to_state(sd);
 313
 314        if (vt->type != V4L2_TUNER_ANALOG_TV)
 315                return -EINVAL;
 316
 317        if (vt->audmode != t->audmode) {
 318                t->audmode = vt->audmode;
 319                mpx_setup(t);
 320        }
 321        return 0;
 322}
 323
 324/* --------------------------------------------------------------------------*/
 325
 326static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = {
 327        .s_tuner = sony_btf_mpx_s_tuner,
 328        .g_tuner = sony_btf_mpx_g_tuner,
 329};
 330
 331static const struct v4l2_subdev_video_ops sony_btf_mpx_video_ops = {
 332        .s_std = sony_btf_mpx_s_std,
 333};
 334
 335static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
 336        .tuner = &sony_btf_mpx_tuner_ops,
 337        .video = &sony_btf_mpx_video_ops,
 338};
 339
 340/* --------------------------------------------------------------------------*/
 341
 342static int sony_btf_mpx_probe(struct i2c_client *client,
 343                                const struct i2c_device_id *id)
 344{
 345        struct sony_btf_mpx *t;
 346        struct v4l2_subdev *sd;
 347
 348        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
 349                return -ENODEV;
 350
 351        v4l_info(client, "chip found @ 0x%x (%s)\n",
 352                        client->addr << 1, client->adapter->name);
 353
 354        t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
 355        if (t == NULL)
 356                return -ENOMEM;
 357
 358        sd = &t->sd;
 359        v4l2_i2c_subdev_init(sd, client, &sony_btf_mpx_ops);
 360
 361        /* Initialize sony_btf_mpx */
 362        t->mpxmode = 0;
 363        t->audmode = V4L2_TUNER_MODE_STEREO;
 364
 365        return 0;
 366}
 367
 368static int sony_btf_mpx_remove(struct i2c_client *client)
 369{
 370        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 371
 372        v4l2_device_unregister_subdev(sd);
 373
 374        return 0;
 375}
 376
 377/* ----------------------------------------------------------------------- */
 378
 379static const struct i2c_device_id sony_btf_mpx_id[] = {
 380        { "sony-btf-mpx", 0 },
 381        { }
 382};
 383MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id);
 384
 385static struct i2c_driver sony_btf_mpx_driver = {
 386        .driver = {
 387                .name   = "sony-btf-mpx",
 388        },
 389        .probe = sony_btf_mpx_probe,
 390        .remove = sony_btf_mpx_remove,
 391        .id_table = sony_btf_mpx_id,
 392};
 393module_i2c_driver(sony_btf_mpx_driver);
 394