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