Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2005-2006 Micronas USA Inc.
0004  */
0005 
0006 #include <linux/module.h>
0007 #include <linux/init.h>
0008 #include <linux/i2c.h>
0009 #include <linux/videodev2.h>
0010 #include <media/tuner.h>
0011 #include <media/v4l2-common.h>
0012 #include <media/v4l2-ioctl.h>
0013 #include <media/v4l2-device.h>
0014 #include <linux/slab.h>
0015 
0016 MODULE_DESCRIPTION("sony-btf-mpx driver");
0017 MODULE_LICENSE("GPL v2");
0018 
0019 static int debug;
0020 module_param(debug, int, 0644);
0021 MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on");
0022 
0023 /* #define MPX_DEBUG */
0024 
0025 /*
0026  * Note:
0027  *
0028  * AS(IF/MPX) pin:      LOW      HIGH/OPEN
0029  * IF/MPX address:   0x42/0x40   0x43/0x44
0030  */
0031 
0032 
0033 static int force_mpx_mode = -1;
0034 module_param(force_mpx_mode, int, 0644);
0035 
0036 struct sony_btf_mpx {
0037     struct v4l2_subdev sd;
0038     int mpxmode;
0039     u32 audmode;
0040 };
0041 
0042 static inline struct sony_btf_mpx *to_state(struct v4l2_subdev *sd)
0043 {
0044     return container_of(sd, struct sony_btf_mpx, sd);
0045 }
0046 
0047 static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
0048 {
0049     u8 buffer[5];
0050     struct i2c_msg msg;
0051 
0052     buffer[0] = dev;
0053     buffer[1] = addr >> 8;
0054     buffer[2] = addr & 0xff;
0055     buffer[3] = val >> 8;
0056     buffer[4] = val & 0xff;
0057     msg.addr = client->addr;
0058     msg.flags = 0;
0059     msg.len = 5;
0060     msg.buf = buffer;
0061     i2c_transfer(client->adapter, &msg, 1);
0062     return 0;
0063 }
0064 
0065 /*
0066  * MPX register values for the BTF-PG472Z:
0067  *
0068  *                                 FM_     NICAM_  SCART_
0069  *          MODUS  SOURCE    ACB   PRESCAL PRESCAL PRESCAL SYSTEM  VOLUME
0070  *         10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
0071  *         ---------------------------------------------------------------
0072  * Auto     1003    0020    0100    2603    5000    XXXX    0001    7500
0073  *
0074  * B/G
0075  *  Mono    1003    0020    0100    2603    5000    XXXX    0003    7500
0076  *  A2      1003    0020    0100    2601    5000    XXXX    0003    7500
0077  *  NICAM   1003    0120    0100    2603    5000    XXXX    0008    7500
0078  *
0079  * I
0080  *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
0081  *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
0082  *
0083  * D/K
0084  *  Mono    1003    0020    0100    2603    5000    XXXX    0004    7500
0085  *  A2-1    1003    0020    0100    2601    5000    XXXX    0004    7500
0086  *  A2-2    1003    0020    0100    2601    5000    XXXX    0005    7500
0087  *  A2-3    1003    0020    0100    2601    5000    XXXX    0007    7500
0088  *  NICAM   1003    0120    0100    2603    5000    XXXX    000B    7500
0089  *
0090  * L/L'
0091  *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
0092  *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
0093  *
0094  * M
0095  *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
0096  *
0097  * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
0098  *
0099  * Bilingual selection in A2/NICAM:
0100  *
0101  *         High byte of SOURCE     Left chan   Right chan
0102  *                 0x01              MAIN         SUB
0103  *                 0x03              MAIN         MAIN
0104  *                 0x04              SUB          SUB
0105  *
0106  * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
0107  * 0x00 (all other bands).  Force mono in A2 with FMONO_A2:
0108  *
0109  *                      FMONO_A2
0110  *                      10/0022
0111  *                      --------
0112  *     Forced mono ON     07F0
0113  *     Forced mono OFF    0190
0114  */
0115 
0116 static const struct {
0117     enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
0118     u16 modus;
0119     u16 source;
0120     u16 acb;
0121     u16 fm_prescale;
0122     u16 nicam_prescale;
0123     u16 scart_prescale;
0124     u16 system;
0125     u16 volume;
0126 } mpx_audio_modes[] = {
0127     /* Auto */  { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
0128                     0x5000, 0x0000, 0x0001, 0x7500 },
0129     /* B/G Mono */  { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
0130                     0x5000, 0x0000, 0x0003, 0x7500 },
0131     /* B/G A2 */    { AUD_A2,   0x1003, 0x0020, 0x0100, 0x2601,
0132                     0x5000, 0x0000, 0x0003, 0x7500 },
0133     /* B/G NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
0134                     0x5000, 0x0000, 0x0008, 0x7500 },
0135     /* I Mono */    { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
0136                     0x7900, 0x0000, 0x000A, 0x7500 },
0137     /* I NICAM */   { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
0138                     0x7900, 0x0000, 0x000A, 0x7500 },
0139     /* D/K Mono */  { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
0140                     0x5000, 0x0000, 0x0004, 0x7500 },
0141     /* D/K A2-1 */  { AUD_A2,   0x1003, 0x0020, 0x0100, 0x2601,
0142                     0x5000, 0x0000, 0x0004, 0x7500 },
0143     /* D/K A2-2 */  { AUD_A2,   0x1003, 0x0020, 0x0100, 0x2601,
0144                     0x5000, 0x0000, 0x0005, 0x7500 },
0145     /* D/K A2-3 */  { AUD_A2,   0x1003, 0x0020, 0x0100, 0x2601,
0146                     0x5000, 0x0000, 0x0007, 0x7500 },
0147     /* D/K NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
0148                     0x5000, 0x0000, 0x000B, 0x7500 },
0149     /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
0150                     0x5000, 0x2200, 0x0009, 0x7500 },
0151     /* L/L' NICAM */{ AUD_NICAM_L,  0x0003, 0x0120, 0x0100, 0x7C03,
0152                     0x5000, 0x0000, 0x0009, 0x7500 },
0153 };
0154 
0155 #define MPX_NUM_MODES   ARRAY_SIZE(mpx_audio_modes)
0156 
0157 static int mpx_setup(struct sony_btf_mpx *t)
0158 {
0159     struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
0160     u16 source = 0;
0161     u8 buffer[3];
0162     struct i2c_msg msg;
0163     int mode = t->mpxmode;
0164 
0165     /* reset MPX */
0166     buffer[0] = 0x00;
0167     buffer[1] = 0x80;
0168     buffer[2] = 0x00;
0169     msg.addr = client->addr;
0170     msg.flags = 0;
0171     msg.len = 3;
0172     msg.buf = buffer;
0173     i2c_transfer(client->adapter, &msg, 1);
0174     buffer[1] = 0x00;
0175     i2c_transfer(client->adapter, &msg, 1);
0176 
0177     if (t->audmode != V4L2_TUNER_MODE_MONO)
0178         mode++;
0179 
0180     if (mpx_audio_modes[mode].audio_mode != AUD_MONO) {
0181         switch (t->audmode) {
0182         case V4L2_TUNER_MODE_MONO:
0183             switch (mpx_audio_modes[mode].audio_mode) {
0184             case AUD_A2:
0185                 source = mpx_audio_modes[mode].source;
0186                 break;
0187             case AUD_NICAM:
0188                 source = 0x0000;
0189                 break;
0190             case AUD_NICAM_L:
0191                 source = 0x0200;
0192                 break;
0193             default:
0194                 break;
0195             }
0196             break;
0197         case V4L2_TUNER_MODE_STEREO:
0198             source = mpx_audio_modes[mode].source;
0199             break;
0200         case V4L2_TUNER_MODE_LANG1:
0201             source = 0x0300;
0202             break;
0203         case V4L2_TUNER_MODE_LANG2:
0204             source = 0x0400;
0205             break;
0206         }
0207         source |= mpx_audio_modes[mode].source & 0x00ff;
0208     } else
0209         source = mpx_audio_modes[mode].source;
0210 
0211     mpx_write(client, 0x10, 0x0030, mpx_audio_modes[mode].modus);
0212     mpx_write(client, 0x12, 0x0008, source);
0213     mpx_write(client, 0x12, 0x0013, mpx_audio_modes[mode].acb);
0214     mpx_write(client, 0x12, 0x000e,
0215             mpx_audio_modes[mode].fm_prescale);
0216     mpx_write(client, 0x12, 0x0010,
0217             mpx_audio_modes[mode].nicam_prescale);
0218     mpx_write(client, 0x12, 0x000d,
0219             mpx_audio_modes[mode].scart_prescale);
0220     mpx_write(client, 0x10, 0x0020, mpx_audio_modes[mode].system);
0221     mpx_write(client, 0x12, 0x0000, mpx_audio_modes[mode].volume);
0222     if (mpx_audio_modes[mode].audio_mode == AUD_A2)
0223         mpx_write(client, 0x10, 0x0022,
0224             t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
0225 
0226 #ifdef MPX_DEBUG
0227     {
0228         u8 buf1[3], buf2[2];
0229         struct i2c_msg msgs[2];
0230 
0231         v4l2_info(client,
0232             "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n",
0233             mpx_audio_modes[mode].modus,
0234             source,
0235             mpx_audio_modes[mode].acb,
0236             mpx_audio_modes[mode].fm_prescale,
0237             mpx_audio_modes[mode].nicam_prescale,
0238             mpx_audio_modes[mode].scart_prescale,
0239             mpx_audio_modes[mode].system,
0240             mpx_audio_modes[mode].volume);
0241         buf1[0] = 0x11;
0242         buf1[1] = 0x00;
0243         buf1[2] = 0x7e;
0244         msgs[0].addr = client->addr;
0245         msgs[0].flags = 0;
0246         msgs[0].len = 3;
0247         msgs[0].buf = buf1;
0248         msgs[1].addr = client->addr;
0249         msgs[1].flags = I2C_M_RD;
0250         msgs[1].len = 2;
0251         msgs[1].buf = buf2;
0252         i2c_transfer(client->adapter, msgs, 2);
0253         v4l2_info(client, "MPX system: %02x%02x\n",
0254                 buf2[0], buf2[1]);
0255         buf1[0] = 0x11;
0256         buf1[1] = 0x02;
0257         buf1[2] = 0x00;
0258         i2c_transfer(client->adapter, msgs, 2);
0259         v4l2_info(client, "MPX status: %02x%02x\n",
0260                 buf2[0], buf2[1]);
0261     }
0262 #endif
0263     return 0;
0264 }
0265 
0266 
0267 static int sony_btf_mpx_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
0268 {
0269     struct sony_btf_mpx *t = to_state(sd);
0270     int default_mpx_mode = 0;
0271 
0272     if (std & V4L2_STD_PAL_BG)
0273         default_mpx_mode = 1;
0274     else if (std & V4L2_STD_PAL_I)
0275         default_mpx_mode = 4;
0276     else if (std & V4L2_STD_PAL_DK)
0277         default_mpx_mode = 6;
0278     else if (std & V4L2_STD_SECAM_L)
0279         default_mpx_mode = 11;
0280 
0281     if (default_mpx_mode != t->mpxmode) {
0282         t->mpxmode = default_mpx_mode;
0283         mpx_setup(t);
0284     }
0285     return 0;
0286 }
0287 
0288 static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
0289 {
0290     struct sony_btf_mpx *t = to_state(sd);
0291 
0292     vt->capability = V4L2_TUNER_CAP_NORM |
0293         V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
0294         V4L2_TUNER_CAP_LANG2;
0295     vt->rxsubchans = V4L2_TUNER_SUB_MONO |
0296         V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
0297         V4L2_TUNER_SUB_LANG2;
0298     vt->audmode = t->audmode;
0299     return 0;
0300 }
0301 
0302 static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
0303 {
0304     struct sony_btf_mpx *t = to_state(sd);
0305 
0306     if (vt->type != V4L2_TUNER_ANALOG_TV)
0307         return -EINVAL;
0308 
0309     if (vt->audmode != t->audmode) {
0310         t->audmode = vt->audmode;
0311         mpx_setup(t);
0312     }
0313     return 0;
0314 }
0315 
0316 /* --------------------------------------------------------------------------*/
0317 
0318 static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = {
0319     .s_tuner = sony_btf_mpx_s_tuner,
0320     .g_tuner = sony_btf_mpx_g_tuner,
0321 };
0322 
0323 static const struct v4l2_subdev_video_ops sony_btf_mpx_video_ops = {
0324     .s_std = sony_btf_mpx_s_std,
0325 };
0326 
0327 static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
0328     .tuner = &sony_btf_mpx_tuner_ops,
0329     .video = &sony_btf_mpx_video_ops,
0330 };
0331 
0332 /* --------------------------------------------------------------------------*/
0333 
0334 static int sony_btf_mpx_probe(struct i2c_client *client,
0335                 const struct i2c_device_id *id)
0336 {
0337     struct sony_btf_mpx *t;
0338     struct v4l2_subdev *sd;
0339 
0340     if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
0341         return -ENODEV;
0342 
0343     v4l_info(client, "chip found @ 0x%x (%s)\n",
0344             client->addr << 1, client->adapter->name);
0345 
0346     t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
0347     if (t == NULL)
0348         return -ENOMEM;
0349 
0350     sd = &t->sd;
0351     v4l2_i2c_subdev_init(sd, client, &sony_btf_mpx_ops);
0352 
0353     /* Initialize sony_btf_mpx */
0354     t->mpxmode = 0;
0355     t->audmode = V4L2_TUNER_MODE_STEREO;
0356 
0357     return 0;
0358 }
0359 
0360 static int sony_btf_mpx_remove(struct i2c_client *client)
0361 {
0362     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0363 
0364     v4l2_device_unregister_subdev(sd);
0365 
0366     return 0;
0367 }
0368 
0369 /* ----------------------------------------------------------------------- */
0370 
0371 static const struct i2c_device_id sony_btf_mpx_id[] = {
0372     { "sony-btf-mpx", 0 },
0373     { }
0374 };
0375 MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id);
0376 
0377 static struct i2c_driver sony_btf_mpx_driver = {
0378     .driver = {
0379         .name   = "sony-btf-mpx",
0380     },
0381     .probe = sony_btf_mpx_probe,
0382     .remove = sony_btf_mpx_remove,
0383     .id_table = sony_btf_mpx_id,
0384 };
0385 module_i2c_driver(sony_btf_mpx_driver);