diff options
Diffstat (limited to 'drivers/media/i2c/tvaudio.c')
| -rw-r--r-- | drivers/media/i2c/tvaudio.c | 257 |
1 files changed, 94 insertions, 163 deletions
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 3b24d3fc186..070c152da95 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -38,7 +38,7 @@ #include <media/tvaudio.h> #include <media/v4l2-device.h> -#include <media/v4l2-chip-ident.h> +#include <media/v4l2-ctrls.h> #include <media/i2c-addr.h> @@ -91,13 +91,13 @@ struct CHIPDESC { audiocmd init; /* which register has which value */ - int leftreg,rightreg,treblereg,bassreg; + int leftreg, rightreg, treblereg, bassreg; - /* initialize with (defaults to 65535/65535/32768/32768 */ - int leftinit,rightinit,trebleinit,bassinit; + /* initialize with (defaults to 65535/32768/32768 */ + int volinit, trebleinit, bassinit; /* functions to convert the values (v4l -> chip) */ - getvalue volfunc,treblefunc,bassfunc; + getvalue volfunc, treblefunc, bassfunc; /* get/set mode */ getrxsubchans getrxsubchans; @@ -113,6 +113,12 @@ struct CHIPDESC { /* current state of the chip */ struct CHIPSTATE { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + struct { + /* volume/balance cluster */ + struct v4l2_ctrl *volume; + struct v4l2_ctrl *balance; + }; /* chip-specific description - should point to an entry at CHIPDESC table */ @@ -122,7 +128,7 @@ struct CHIPSTATE { audiocmd shadow; /* current settings */ - __u16 left, right, treble, bass, muted; + u16 muted; int prevmode; int radio; int input; @@ -138,6 +144,11 @@ static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd) return container_of(sd, struct CHIPSTATE, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct CHIPSTATE, hdl)->sd; +} + /* ---------------------------------------------------------------------- */ /* i2c I/O functions */ @@ -1523,8 +1534,7 @@ static struct CHIPDESC chiplist[] = { .rightreg = TDA9875_MVR, .bassreg = TDA9875_MBA, .treblereg = TDA9875_MTR, - .leftinit = 58880, - .rightinit = 58880, + .volinit = 58880, }, { .name = "tda9850", @@ -1618,7 +1628,8 @@ static struct CHIPDESC chiplist[] = { .inputreg = -1, .inputmap = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC }, - .inputmute = TEA6300_S_GMU, + .inputmute = TEA6420_S_GMU, + .inputmask = 0x07, }, { .name = "tda8425", @@ -1679,121 +1690,39 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ -static int tvaudio_g_ctrl(struct v4l2_subdev *sd, - struct v4l2_control *ctrl) +static int tvaudio_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = to_sd(ctrl); struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (!(desc->flags & CHIP_HAS_INPUTSEL)) - break; - ctrl->value=chip->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - ctrl->value = max(chip->left,chip->right); - return 0; - case V4L2_CID_AUDIO_BALANCE: - { - int volume; - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - volume = max(chip->left,chip->right); - if (volume) - ctrl->value=(32768*min(chip->left,chip->right))/volume; - else - ctrl->value=32768; - return 0; - } - case V4L2_CID_AUDIO_BASS: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - ctrl->value = chip->bass; - return 0; - case V4L2_CID_AUDIO_TREBLE: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - ctrl->value = chip->treble; - return 0; - } - return -EINVAL; -} - -static int tvaudio_s_ctrl(struct v4l2_subdev *sd, - struct v4l2_control *ctrl) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (!(desc->flags & CHIP_HAS_INPUTSEL)) - break; - - if (ctrl->value < 0 || ctrl->value >= 2) - return -ERANGE; - chip->muted = ctrl->value; + chip->muted = ctrl->val; if (chip->muted) chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask); else chip_write_masked(chip,desc->inputreg, desc->inputmap[chip->input],desc->inputmask); return 0; - case V4L2_CID_AUDIO_VOLUME: - { - int volume,balance; - - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - - volume = max(chip->left,chip->right); - if (volume) - balance=(32768*min(chip->left,chip->right))/volume; - else - balance=32768; - - volume=ctrl->value; - chip->left = (min(65536 - balance,32768) * volume) / 32768; - chip->right = (min(balance,volume *(__u16)32768)) / 32768; + case V4L2_CID_AUDIO_VOLUME: { + u32 volume, balance; + u32 left, right; - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - - return 0; - } - case V4L2_CID_AUDIO_BALANCE: - { - int volume, balance; - - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - - volume = max(chip->left, chip->right); - balance = ctrl->value; - chip->left = (min(65536 - balance, 32768) * volume) / 32768; - chip->right = (min(balance, volume * (__u16)32768)) / 32768; - - chip_write(chip, desc->leftreg, desc->volfunc(chip->left)); - chip_write(chip, desc->rightreg, desc->volfunc(chip->right)); + volume = chip->volume->val; + balance = chip->balance->val; + left = (min(65536U - balance, 32768U) * volume) / 32768U; + right = (min(balance, 32768U) * volume) / 32768U; + chip_write(chip, desc->leftreg, desc->volfunc(left)); + chip_write(chip, desc->rightreg, desc->volfunc(right)); return 0; } case V4L2_CID_AUDIO_BASS: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - chip->bass = ctrl->value; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - + chip_write(chip, desc->bassreg, desc->bassfunc(ctrl->val)); return 0; case V4L2_CID_AUDIO_TREBLE: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - chip->treble = ctrl->value; - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); - + chip_write(chip, desc->treblereg, desc->treblefunc(ctrl->val)); return 0; } return -EINVAL; @@ -1812,35 +1741,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd) return 0; } -static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - if (desc->flags & CHIP_HAS_INPUTSEL) - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - break; - case V4L2_CID_AUDIO_VOLUME: - if (desc->flags & CHIP_HAS_VOLUME) - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); - break; - case V4L2_CID_AUDIO_BALANCE: - if (desc->flags & CHIP_HAS_VOLUME) - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - break; - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - break; - default: - break; - } - return -EINVAL; -} - static int tvaudio_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) { @@ -1860,7 +1760,7 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd, return 0; } -static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int tvaudio_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; @@ -1902,7 +1802,7 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) vt->audmode = chip->audmode; vt->rxsubchans = desc->getrxsubchans(chip); - vt->capability = V4L2_TUNER_CAP_STEREO | + vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; return 0; @@ -1916,7 +1816,7 @@ static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std) return 0; } -static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; @@ -1937,21 +1837,31 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr return 0; } -static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +static int tvaudio_log_status(struct v4l2_subdev *sd) { - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct CHIPSTATE *chip = to_state(sd); + struct CHIPDESC *desc = chip->desc; - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0); + v4l2_info(sd, "Chip: %s\n", desc->name); + v4l2_ctrl_handler_log_status(&chip->hdl, sd->name); + return 0; } /* ----------------------------------------------------------------------- */ -static const struct v4l2_subdev_core_ops tvaudio_core_ops = { - .g_chip_ident = tvaudio_g_chip_ident, - .queryctrl = tvaudio_queryctrl, - .g_ctrl = tvaudio_g_ctrl, +static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = { .s_ctrl = tvaudio_s_ctrl, - .s_std = tvaudio_s_std, +}; + +static const struct v4l2_subdev_core_ops tvaudio_core_ops = { + .log_status = tvaudio_log_status, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = { @@ -1965,10 +1875,15 @@ static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = { .s_routing = tvaudio_s_routing, }; +static const struct v4l2_subdev_video_ops tvaudio_video_ops = { + .s_std = tvaudio_s_std, +}; + static const struct v4l2_subdev_ops tvaudio_ops = { .core = &tvaudio_core_ops, .tuner = &tvaudio_tuner_ops, .audio = &tvaudio_audio_ops, + .video = &tvaudio_video_ops, }; /* ----------------------------------------------------------------------- */ @@ -1990,7 +1905,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * printk("\n"); } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; sd = &chip->sd; @@ -2010,7 +1925,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * } if (desc->name == NULL) { v4l2_dbg(1, debug, sd, "no matching chip description found\n"); - kfree(chip); return -EIO; } v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); @@ -2035,6 +1949,10 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * else chip_cmd(chip, "init", &desc->init); + v4l2_ctrl_handler_init(&chip->hdl, 5); + if (desc->flags & CHIP_HAS_INPUTSEL) + v4l2_ctrl_new_std(&chip->hdl, &tvaudio_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); if (desc->flags & CHIP_HAS_VOLUME) { if (!desc->volfunc) { /* This shouldn't be happen. Warn user, but keep working @@ -2043,12 +1961,14 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * v4l2_info(sd, "volume callback undefined!\n"); desc->flags &= ~CHIP_HAS_VOLUME; } else { - chip->left = desc->leftinit ? desc->leftinit : 65535; - chip->right = desc->rightinit ? desc->rightinit : 65535; - chip_write(chip, desc->leftreg, - desc->volfunc(chip->left)); - chip_write(chip, desc->rightreg, - desc->volfunc(chip->right)); + chip->volume = v4l2_ctrl_new_std(&chip->hdl, + &tvaudio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, + 0, 65535, 65535 / 100, + desc->volinit ? desc->volinit : 65535); + chip->balance = v4l2_ctrl_new_std(&chip->hdl, + &tvaudio_ctrl_ops, V4L2_CID_AUDIO_BALANCE, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_cluster(2, &chip->volume); } } if (desc->flags & CHIP_HAS_BASSTREBLE) { @@ -2059,17 +1979,27 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * v4l2_info(sd, "bass/treble callbacks undefined!\n"); desc->flags &= ~CHIP_HAS_BASSTREBLE; } else { - chip->treble = desc->trebleinit ? - desc->trebleinit : 32768; - chip->bass = desc->bassinit ? - desc->bassinit : 32768; - chip_write(chip, desc->bassreg, - desc->bassfunc(chip->bass)); - chip_write(chip, desc->treblereg, - desc->treblefunc(chip->treble)); + v4l2_ctrl_new_std(&chip->hdl, + &tvaudio_ctrl_ops, V4L2_CID_AUDIO_BASS, + 0, 65535, 65535 / 100, + desc->bassinit ? desc->bassinit : 32768); + v4l2_ctrl_new_std(&chip->hdl, + &tvaudio_ctrl_ops, V4L2_CID_AUDIO_TREBLE, + 0, 65535, 65535 / 100, + desc->trebleinit ? desc->trebleinit : 32768); } } + sd->ctrl_handler = &chip->hdl; + if (chip->hdl.error) { + int err = chip->hdl.error; + + v4l2_ctrl_handler_free(&chip->hdl); + return err; + } + /* set controls to the default values */ + v4l2_ctrl_handler_setup(&chip->hdl); + chip->thread = NULL; init_timer(&chip->wt); if (desc->flags & CHIP_NEED_CHECKMODE) { @@ -2083,7 +2013,8 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * /* start async thread */ chip->wt.function = chip_thread_wake; chip->wt.data = (unsigned long)chip; - chip->thread = kthread_run(chip_thread, chip, client->name); + chip->thread = kthread_run(chip_thread, chip, "%s", + client->name); if (IS_ERR(chip->thread)) { v4l2_warn(sd, "failed to create kthread\n"); chip->thread = NULL; @@ -2105,7 +2036,7 @@ static int tvaudio_remove(struct i2c_client *client) } v4l2_device_unregister_subdev(sd); - kfree(chip); + v4l2_ctrl_handler_free(&chip->hdl); return 0; } |
