linux/drivers/media/i2c/wm8775.c
<<
>>
Prefs
   1/*
   2 * wm8775 - driver version 0.0.1
   3 *
   4 * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
   5 *
   6 * Based on saa7115 driver
   7 *
   8 * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
   9 * - Cleanup
  10 * - V4L2 API update
  11 * - sound fixes
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 */
  27
  28#include <linux/module.h>
  29#include <linux/types.h>
  30#include <linux/slab.h>
  31#include <linux/ioctl.h>
  32#include <asm/uaccess.h>
  33#include <linux/i2c.h>
  34#include <linux/videodev2.h>
  35#include <media/v4l2-device.h>
  36#include <media/v4l2-ctrls.h>
  37#include <media/wm8775.h>
  38
  39MODULE_DESCRIPTION("wm8775 driver");
  40MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
  41MODULE_LICENSE("GPL");
  42
  43
  44
  45/* ----------------------------------------------------------------------- */
  46
  47enum {
  48        R7 = 7, R11 = 11,
  49        R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
  50        TOT_REGS
  51};
  52
  53#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
  54#define ALC_EN 0x100  /* R17: ALC enable */
  55
  56struct wm8775_state {
  57        struct v4l2_subdev sd;
  58        struct v4l2_ctrl_handler hdl;
  59        struct v4l2_ctrl *mute;
  60        struct v4l2_ctrl *vol;
  61        struct v4l2_ctrl *bal;
  62        struct v4l2_ctrl *loud;
  63        u8 input;               /* Last selected input (0-0xf) */
  64};
  65
  66static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
  67{
  68        return container_of(sd, struct wm8775_state, sd);
  69}
  70
  71static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
  72{
  73        return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd;
  74}
  75
  76static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
  77{
  78        struct i2c_client *client = v4l2_get_subdevdata(sd);
  79        int i;
  80
  81        if (reg < 0 || reg >= TOT_REGS) {
  82                v4l2_err(sd, "Invalid register R%d\n", reg);
  83                return -1;
  84        }
  85
  86        for (i = 0; i < 3; i++)
  87                if (i2c_smbus_write_byte_data(client,
  88                                (reg << 1) | (val >> 8), val & 0xff) == 0)
  89                        return 0;
  90        v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
  91        return -1;
  92}
  93
  94static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
  95{
  96        struct wm8775_state *state = to_state(sd);
  97        u8 vol_l, vol_r;
  98        int muted = 0 != state->mute->val;
  99        u16 volume = (u16)state->vol->val;
 100        u16 balance = (u16)state->bal->val;
 101
 102        /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
 103        vol_l = (min(65536 - balance, 32768) * volume) >> 23;
 104        vol_r = (min(balance, (u16)32768) * volume) >> 23;
 105
 106        /* Mute */
 107        if (muted || quietly)
 108                wm8775_write(sd, R21, 0x0c0 | state->input);
 109
 110        wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
 111        wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
 112
 113        /* Un-mute */
 114        if (!muted)
 115                wm8775_write(sd, R21, state->input);
 116}
 117
 118static int wm8775_s_routing(struct v4l2_subdev *sd,
 119                            u32 input, u32 output, u32 config)
 120{
 121        struct wm8775_state *state = to_state(sd);
 122
 123        /* There are 4 inputs and one output. Zero or more inputs
 124           are multiplexed together to the output. Hence there are
 125           16 combinations.
 126           If only one input is active (the normal case) then the
 127           input values 1, 2, 4 or 8 should be used. */
 128        if (input > 15) {
 129                v4l2_err(sd, "Invalid input %d.\n", input);
 130                return -EINVAL;
 131        }
 132        state->input = input;
 133        if (!v4l2_ctrl_g_ctrl(state->mute))
 134                return 0;
 135        if (!v4l2_ctrl_g_ctrl(state->vol))
 136                return 0;
 137        if (!v4l2_ctrl_g_ctrl(state->bal))
 138                return 0;
 139        wm8775_set_audio(sd, 1);
 140        return 0;
 141}
 142
 143static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
 144{
 145        struct v4l2_subdev *sd = to_sd(ctrl);
 146
 147        switch (ctrl->id) {
 148        case V4L2_CID_AUDIO_MUTE:
 149        case V4L2_CID_AUDIO_VOLUME:
 150        case V4L2_CID_AUDIO_BALANCE:
 151                wm8775_set_audio(sd, 0);
 152                return 0;
 153        case V4L2_CID_AUDIO_LOUDNESS:
 154                wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
 155                return 0;
 156        }
 157        return -EINVAL;
 158}
 159
 160static int wm8775_log_status(struct v4l2_subdev *sd)
 161{
 162        struct wm8775_state *state = to_state(sd);
 163
 164        v4l2_info(sd, "Input: %d\n", state->input);
 165        v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
 166        return 0;
 167}
 168
 169static int wm8775_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
 170{
 171        wm8775_set_audio(sd, 0);
 172        return 0;
 173}
 174
 175/* ----------------------------------------------------------------------- */
 176
 177static const struct v4l2_ctrl_ops wm8775_ctrl_ops = {
 178        .s_ctrl = wm8775_s_ctrl,
 179};
 180
 181static const struct v4l2_subdev_core_ops wm8775_core_ops = {
 182        .log_status = wm8775_log_status,
 183        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
 184        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
 185        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
 186        .g_ctrl = v4l2_subdev_g_ctrl,
 187        .s_ctrl = v4l2_subdev_s_ctrl,
 188        .queryctrl = v4l2_subdev_queryctrl,
 189        .querymenu = v4l2_subdev_querymenu,
 190};
 191
 192static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
 193        .s_frequency = wm8775_s_frequency,
 194};
 195
 196static const struct v4l2_subdev_audio_ops wm8775_audio_ops = {
 197        .s_routing = wm8775_s_routing,
 198};
 199
 200static const struct v4l2_subdev_ops wm8775_ops = {
 201        .core = &wm8775_core_ops,
 202        .tuner = &wm8775_tuner_ops,
 203        .audio = &wm8775_audio_ops,
 204};
 205
 206/* ----------------------------------------------------------------------- */
 207
 208/* i2c implementation */
 209
 210/*
 211 * Generic i2c probe
 212 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 213 */
 214
 215static int wm8775_probe(struct i2c_client *client,
 216                        const struct i2c_device_id *id)
 217{
 218        struct wm8775_state *state;
 219        struct v4l2_subdev *sd;
 220        int err;
 221        bool is_nova_s = false;
 222
 223        if (client->dev.platform_data) {
 224                struct wm8775_platform_data *data = client->dev.platform_data;
 225                is_nova_s = data->is_nova_s;
 226        }
 227
 228        /* Check if the adapter supports the needed features */
 229        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 230                return -EIO;
 231
 232        v4l_info(client, "chip found @ 0x%02x (%s)\n",
 233                        client->addr << 1, client->adapter->name);
 234
 235        state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
 236        if (state == NULL)
 237                return -ENOMEM;
 238        sd = &state->sd;
 239        v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
 240        state->input = 2;
 241
 242        v4l2_ctrl_handler_init(&state->hdl, 4);
 243        state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
 244                        V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
 245        state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
 246                        V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
 247        state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
 248                        V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
 249        state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
 250                        V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
 251        sd->ctrl_handler = &state->hdl;
 252        err = state->hdl.error;
 253        if (err) {
 254                v4l2_ctrl_handler_free(&state->hdl);
 255                return err;
 256        }
 257
 258        /* Initialize wm8775 */
 259
 260        /* RESET */
 261        wm8775_write(sd, R23, 0x000);
 262        /* Disable zero cross detect timeout */
 263        wm8775_write(sd, R7, 0x000);
 264        /* HPF enable, left justified, 24-bit (Philips) mode */
 265        wm8775_write(sd, R11, 0x021);
 266        /* Master mode, clock ratio 256fs */
 267        wm8775_write(sd, R12, 0x102);
 268        /* Powered up */
 269        wm8775_write(sd, R13, 0x000);
 270
 271        if (!is_nova_s) {
 272                /* ADC gain +2.5dB, enable zero cross */
 273                wm8775_write(sd, R14, 0x1d4);
 274                /* ADC gain +2.5dB, enable zero cross */
 275                wm8775_write(sd, R15, 0x1d4);
 276                /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
 277                wm8775_write(sd, R16, 0x1bf);
 278                /* Enable gain control, use zero cross detection,
 279                   ALC hold time 42.6 ms */
 280                wm8775_write(sd, R17, 0x185);
 281        } else {
 282                /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
 283                wm8775_write(sd, R16, 0x1bb);
 284                /* Set ALC mode and hold time */
 285                wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
 286        }
 287        /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
 288        wm8775_write(sd, R18, 0x0a2);
 289        /* Enable noise gate, threshold -72dBfs */
 290        wm8775_write(sd, R19, 0x005);
 291        if (!is_nova_s) {
 292                /* Transient window 4ms, lower PGA gain limit -1dB */
 293                wm8775_write(sd, R20, 0x07a);
 294                /* LRBOTH = 1, use input 2. */
 295                wm8775_write(sd, R21, 0x102);
 296        } else {
 297                /* Transient window 4ms, ALC min gain -5dB  */
 298                wm8775_write(sd, R20, 0x0fb);
 299
 300                wm8775_set_audio(sd, 1);      /* set volume/mute/mux */
 301        }
 302        return 0;
 303}
 304
 305static int wm8775_remove(struct i2c_client *client)
 306{
 307        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 308        struct wm8775_state *state = to_state(sd);
 309
 310        v4l2_device_unregister_subdev(sd);
 311        v4l2_ctrl_handler_free(&state->hdl);
 312        return 0;
 313}
 314
 315static const struct i2c_device_id wm8775_id[] = {
 316        { "wm8775", 0 },
 317        { }
 318};
 319MODULE_DEVICE_TABLE(i2c, wm8775_id);
 320
 321static struct i2c_driver wm8775_driver = {
 322        .driver = {
 323                .owner  = THIS_MODULE,
 324                .name   = "wm8775",
 325        },
 326        .probe          = wm8775_probe,
 327        .remove         = wm8775_remove,
 328        .id_table       = wm8775_id,
 329};
 330
 331module_i2c_driver(wm8775_driver);
 332