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