diff options
Diffstat (limited to 'drivers/media/video/msp3400-driver.c')
-rw-r--r-- | drivers/media/video/msp3400-driver.c | 238 |
1 files changed, 109 insertions, 129 deletions
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index c0c87e06259b..7a11f3159e32 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -42,7 +42,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ @@ -53,6 +54,7 @@ #include <linux/videodev.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-i2c-drv-legacy.h> #include <media/tvaudio.h> #include <media/msp3400.h> #include <linux/kthread.h> @@ -71,7 +73,8 @@ int msp_debug; /* msp_debug output */ int msp_once; /* no continous stereo monitoring */ int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ -int msp_standard = 1; /* Override auto detect of audio msp_standard, if needed. */ +int msp_standard = 1; /* Override auto detect of audio msp_standard, + if needed. */ int msp_dolby; int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual @@ -81,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual module_param(opmode, int, 0444); /* read-write */ -module_param_named(once,msp_once, bool, 0644); -module_param_named(debug,msp_debug, int, 0644); -module_param_named(stereo_threshold,msp_stereo_thresh, int, 0644); -module_param_named(standard,msp_standard, int, 0644); -module_param_named(amsound,msp_amsound, bool, 0644); -module_param_named(dolby,msp_dolby, bool, 0644); +module_param_named(once, msp_once, bool, 0644); +module_param_named(debug, msp_debug, int, 0644); +module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); +module_param_named(standard, msp_standard, int, 0644); +module_param_named(amsound, msp_amsound, bool, 0644); +module_param_named(dolby, msp_dolby, bool, 0644); MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); @@ -160,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); + v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", + dev, addr, retval); return retval; } @@ -190,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); + v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", + dev, addr, val); for (err = 0; err < 3; err++) { if (i2c_master_send(client, buffer, 5) == 5) break; @@ -199,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } @@ -273,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) state->acb = 0xf60; /* Mute Input and SCART 1 Output */ v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); + scart_names[in], out, state->acb); msp_write_dsp(client, 0x13, state->acb); /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ @@ -292,7 +297,8 @@ void msp_set_audio(struct i2c_client *client) val = (state->volume * 0x7f / 65535) << 8; v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", - state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no", + state->muted ? "on" : "off", + state->scan_in_progress ? "yes" : "no", state->volume); msp_write_dsp(client, 0x0000, val); @@ -681,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a); switch (*a) { - case 1024000: - state->i2s_mode = 0; - break; - case 2048000: - state->i2s_mode = 1; - break; - default: - return -EINVAL; + case 1024000: + state->i2s_mode = 0; + break; + case 2048000: + state->i2s_mode = 1; + break; + default: + return -EINVAL; } break; } @@ -698,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - default: - break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; } if (!state->has_sound_processing) return -EINVAL; switch (qc->id) { - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); - default: - return -EINVAL; + case V4L2_CID_AUDIO_LOUDNESS: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; } } @@ -735,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) state->volume, state->muted ? " (muted)" : ""); if (state->has_sound_processing) { v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", - state->balance, state->bass, state->treble, + state->balance, state->bass, + state->treble, state->loudness ? "on" : "off"); } switch (state->mode) { case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; case MSP_MODE_FM_RADIO: p = "FM Radio"; break; - case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break; + case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; @@ -772,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); + return v4l2_chip_ident_i2c_client(client, arg, state->ident, + (state->rev1 << 16) | state->rev2); default: /* unknown */ @@ -783,7 +791,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) static int msp_suspend(struct i2c_client *client, pm_message_t state) { - v4l_dbg(1, msp_debug, client, "suspend\n"); msp_reset(client); return 0; @@ -791,7 +798,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state) static int msp_resume(struct i2c_client *client) { - v4l_dbg(1, msp_debug, client, "resume\n"); msp_wake_thread(client); return 0; @@ -799,11 +805,8 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver; - -static int msp_attach(struct i2c_adapter *adapter, int address, int kind) +static int msp_probe(struct i2c_client *client) { - struct i2c_client *client; struct msp_state *state; int (*thread_func)(void *data) = NULL; int msp_hard; @@ -812,26 +815,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_product, msp_prod_hi, msp_prod_lo; int msp_rom; - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) { - kfree(client); + if (!state) return -ENOMEM; - } i2c_set_clientdata(client, state); @@ -853,12 +846,13 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->rev1 = msp_read_dsp(client, 0x1e); if (state->rev1 != -1) state->rev2 = msp_read_dsp(client, 0x1f); - v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); + v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", + state->rev1, state->rev2); if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); + v4l_dbg(1, msp_debug, client, + "not an msp3400 (cannot read chip version)\n"); kfree(state); - kfree(client); - return 0; + return -ENODEV; } msp_set_audio(client); @@ -874,37 +868,55 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) msp_family, msp_product, msp_revision, msp_hard, msp_rom); /* Rev B=2, C=3, D=4, G=7 */ - state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; + state->ident = msp_family * 10000 + 4000 + msp_product * 10 + + msp_revision - '@'; /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ - state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; + state->has_nicam = + msp_prod_hi == 1 || msp_prod_hi == 5; /* Has radio support: was added with revision G */ - state->has_radio = msp_revision >= 'G'; + state->has_radio = + msp_revision >= 'G'; /* Has headphones output: not for stripped down products */ - state->has_headphones = msp_prod_lo < 5; + state->has_headphones = + msp_prod_lo < 5; /* Has scart2 input: not in stripped down products of the '3' family */ - state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7; + state->has_scart2 = + msp_family >= 4 || msp_prod_lo < 7; /* Has scart3 input: not in stripped down products of the '3' family */ - state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5; + state->has_scart3 = + msp_family >= 4 || msp_prod_lo < 5; /* Has scart4 input: not in pre D revisions, not in stripped D revs */ - state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); - /* Has scart2 output: not in stripped down products of the '3' family */ - state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5; + state->has_scart4 = + msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); + /* Has scart2 output: not in stripped down products of + * the '3' family */ + state->has_scart2_out = + msp_family >= 4 || msp_prod_lo < 5; /* Has scart2 a volume control? Not in pre-D revisions. */ - state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out; + state->has_scart2_out_volume = + msp_revision > 'C' && state->has_scart2_out; /* Has a configurable i2s out? */ - state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7; - /* Has subwoofer output: not in pre-D revs and not in stripped down products */ - state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5; - /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in - stripped down products */ - state->has_sound_processing = msp_prod_lo < 7; + state->has_i2s_conf = + msp_revision >= 'G' && msp_prod_lo < 7; + /* Has subwoofer output: not in pre-D revs and not in stripped down + * products */ + state->has_subwoofer = + msp_revision >= 'D' && msp_prod_lo < 5; + /* Has soundprocessing (bass/treble/balance/loudness/equalizer): + * not in stripped down products */ + state->has_sound_processing = + msp_prod_lo < 7; /* Has Virtual Dolby Surround: only in msp34x1 */ - state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1; + state->has_virtual_dolby_surround = + msp_revision == 'G' && msp_prod_lo == 1; /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ - state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2; - /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */ - state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; + state->has_dolby_pro_logic = + msp_revision == 'G' && msp_prod_lo == 2; + /* The msp343xG supports BTSC only and cannot do Automatic Standard + * Detection. */ + state->force_btsc = + msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; state->opmode = opmode; if (state->opmode == OPMODE_AUTO) { @@ -919,32 +931,33 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) - printk("supports nicam and radio, "); + printk(KERN_CONT "supports nicam and radio, "); else if (state->has_nicam) - printk("supports nicam, "); + printk(KERN_CONT "supports nicam, "); else if (state->has_radio) - printk("supports radio, "); - printk("mode is "); + printk(KERN_CONT "supports radio, "); + printk(KERN_CONT "mode is "); /* version-specific initialization */ switch (state->opmode) { case OPMODE_MANUAL: - printk("manual"); + printk(KERN_CONT "manual"); thread_func = msp3400c_thread; break; case OPMODE_AUTODETECT: - printk("autodetect"); + printk(KERN_CONT "autodetect"); thread_func = msp3410d_thread; break; case OPMODE_AUTOSELECT: - printk("autodetect and autoselect"); + printk(KERN_CONT "autodetect and autoselect"); thread_func = msp34xxg_thread; break; } - printk("\n"); + printk(KERN_CONT "\n"); /* startup control thread if needed */ if (thread_func) { @@ -954,24 +967,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } - - /* done */ - i2c_attach_client(client); - return 0; } -static int msp_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, msp_attach); - return 0; -} - -static int msp_detach(struct i2c_client *client) +static int msp_remove(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int err; /* shutdown control thread */ if (state->kthread) { @@ -980,43 +981,22 @@ static int msp_detach(struct i2c_client *client) } msp_reset(client); - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .id = I2C_DRIVERID_MSP3400, - .attach_adapter = msp_probe, - .detach_client = msp_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "msp3400", + .driverid = I2C_DRIVERID_MSP3400, + .command = msp_command, + .probe = msp_probe, + .remove = msp_remove, .suspend = msp_suspend, - .resume = msp_resume, - .command = msp_command, - .driver = { - .name = "msp3400", - }, + .resume = msp_resume, }; -static int __init msp3400_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit msp3400_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. |