linux/drivers/media/video/tlv320aic23b.c
<<
>>
Prefs
   1/*
   2 * tlv320aic23b - driver version 0.0.1
   3 *
   4 * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
   5 *
   6 * Based on wm8775 driver
   7 *
   8 * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
   9 * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 */
  25
  26#include <linux/module.h>
  27#include <linux/types.h>
  28#include <linux/ioctl.h>
  29#include <asm/uaccess.h>
  30#include <linux/i2c.h>
  31#include <linux/i2c-id.h>
  32#include <linux/videodev.h>
  33#include <media/v4l2-common.h>
  34
  35MODULE_DESCRIPTION("tlv320aic23b driver");
  36MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
  37MODULE_LICENSE("GPL");
  38
  39static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
  40
  41
  42I2C_CLIENT_INSMOD;
  43
  44/* ----------------------------------------------------------------------- */
  45
  46struct tlv320aic23b_state {
  47        u8 muted;
  48};
  49
  50static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
  51{
  52        int i;
  53
  54        if ((reg < 0 || reg > 9) && (reg != 15)) {
  55                v4l_err(client, "Invalid register R%d\n", reg);
  56                return -1;
  57        }
  58
  59        for (i = 0; i < 3; i++) {
  60                if (i2c_smbus_write_byte_data(client, (reg << 1) |
  61                                        (val >> 8), val & 0xff) == 0) {
  62                        return 0;
  63                }
  64        }
  65        v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
  66        return -1;
  67}
  68
  69static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
  70                          void *arg)
  71{
  72        struct tlv320aic23b_state *state = i2c_get_clientdata(client);
  73        struct v4l2_control *ctrl = arg;
  74        u32* freq = arg;
  75
  76        switch (cmd) {
  77        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
  78                switch (*freq) {
  79                        case 32000: /* set sample rate to 32 kHz */
  80                                tlv320aic23b_write(client, 8, 0x018);
  81                                break;
  82                        case 44100: /* set sample rate to 44.1 kHz */
  83                                tlv320aic23b_write(client, 8, 0x022);
  84                                break;
  85                        case 48000: /* set sample rate to 48 kHz */
  86                                tlv320aic23b_write(client, 8, 0x000);
  87                                break;
  88                        default:
  89                                return -EINVAL;
  90                }
  91                break;
  92
  93        case VIDIOC_G_CTRL:
  94                if (ctrl->id != V4L2_CID_AUDIO_MUTE)
  95                        return -EINVAL;
  96                ctrl->value = state->muted;
  97                break;
  98
  99        case VIDIOC_S_CTRL:
 100                if (ctrl->id != V4L2_CID_AUDIO_MUTE)
 101                        return -EINVAL;
 102                state->muted = ctrl->value;
 103                tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
 104                /* set gain on both channels to +3.0 dB */
 105                if (!state->muted)
 106                        tlv320aic23b_write(client, 0, 0x119);
 107                break;
 108
 109        case VIDIOC_LOG_STATUS:
 110                v4l_info(client, "Input: %s\n",
 111                            state->muted ? "muted" : "active");
 112                break;
 113
 114        default:
 115                return -EINVAL;
 116        }
 117        return 0;
 118}
 119
 120/* ----------------------------------------------------------------------- */
 121
 122/* i2c implementation */
 123
 124/*
 125 * Generic i2c probe
 126 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 127 */
 128
 129static struct i2c_driver i2c_driver;
 130
 131static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
 132{
 133        struct i2c_client *client;
 134        struct tlv320aic23b_state *state;
 135
 136        /* Check if the adapter supports the needed features */
 137        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 138                return 0;
 139
 140        client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
 141        if (client == 0)
 142                return -ENOMEM;
 143
 144        client->addr = address;
 145        client->adapter = adapter;
 146        client->driver = &i2c_driver;
 147        snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
 148
 149        v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
 150
 151        state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
 152        if (state == NULL) {
 153                kfree(client);
 154                return -ENOMEM;
 155        }
 156        state->muted = 0;
 157        i2c_set_clientdata(client, state);
 158
 159        /* initialize tlv320aic23b */
 160        tlv320aic23b_write(client, 15, 0x000);  /* RESET */
 161        tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
 162        tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
 163        tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
 164        tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
 165        tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
 166
 167        i2c_attach_client(client);
 168
 169        return 0;
 170}
 171
 172static int tlv320aic23b_probe(struct i2c_adapter *adapter)
 173{
 174        if (adapter->class & I2C_CLASS_TV_ANALOG)
 175                return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
 176        return 0;
 177}
 178
 179static int tlv320aic23b_detach(struct i2c_client *client)
 180{
 181        int err;
 182
 183        err = i2c_detach_client(client);
 184        if (err) {
 185                return err;
 186        }
 187        kfree(client);
 188
 189        return 0;
 190}
 191
 192/* ----------------------------------------------------------------------- */
 193
 194/* i2c implementation */
 195static struct i2c_driver i2c_driver = {
 196        .driver = {
 197                .name = "tlv320aic23b",
 198        },
 199        .id             = I2C_DRIVERID_TLV320AIC23B,
 200        .attach_adapter = tlv320aic23b_probe,
 201        .detach_client  = tlv320aic23b_detach,
 202        .command        = tlv320aic23b_command,
 203};
 204
 205
 206static int __init tlv320aic23b_init_module(void)
 207{
 208        return i2c_add_driver(&i2c_driver);
 209}
 210
 211static void __exit tlv320aic23b_cleanup_module(void)
 212{
 213        i2c_del_driver(&i2c_driver);
 214}
 215
 216module_init(tlv320aic23b_init_module);
 217module_exit(tlv320aic23b_cleanup_module);
 218