diff options
Diffstat (limited to 'target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c')
-rw-r--r-- | target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c | 583 |
1 files changed, 0 insertions, 583 deletions
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c deleted file mode 100644 index 7e6f9acbb3..0000000000 --- a/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c +++ /dev/null @@ -1,583 +0,0 @@ -/* - * sound/ubicom32/ubi32-cs4350.c - * Interface to ubicom32 virtual audio peripheral - using CS4350 DAC - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - */ - -#include <linux/i2c.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <sound/core.h> -#include <sound/tlv.h> -#include <sound/control.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include "ubi32.h" - -#define DRIVER_NAME "snd-ubi32-cs4350" - -/* - * Module properties - */ -static const struct i2c_device_id snd_ubi32_cs4350_id[] = { - {"cs4350", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ubicom32audio_id); - -static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ - -/* - * The dB scale for the Cirrus Logic cs4350. The output range is from - * -127.5 dB to 0 dB. - */ -static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4350_db, -12750, 50, 0); - -#define ubi32_cs4350_mute_info snd_ctl_boolean_stereo_info - -/* - * Private data for cs4350 chip - */ -struct ubi32_cs4350_priv { - /* - * The current volume settings - */ - uint8_t volume[2]; - - /* - * Bitmask of mutes MSB (unused, ..., unused, right_ch, left_ch) LSB - */ - uint8_t mute; - - /* - * Lock to protect this struct because callbacks are not atomic. - */ - spinlock_t lock; -}; - -/* - * The info for the cs4350. The volume currently has one channel, - * and 255 possible settings. - */ -static int ubi32_cs4350_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 255; // 8 bits in cirrus logic cs4350 volume register - return 0; -} - -static int ubi32_cs4350_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); - struct ubi32_cs4350_priv *cs4350_priv; - unsigned long flags; - - cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); - - spin_lock_irqsave(&cs4350_priv->lock, flags); - - ucontrol->value.integer.value[0] = cs4350_priv->volume[0]; - ucontrol->value.integer.value[1] = cs4350_priv->volume[1]; - - spin_unlock_irqrestore(&cs4350_priv->lock, flags); - - return 0; -} - -static int ubi32_cs4350_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); - struct i2c_client *client = (struct i2c_client *)ubi32_priv->client; - struct ubi32_cs4350_priv *cs4350_priv; - unsigned long flags; - int ret, changed; - char send[2]; - uint8_t volume_reg_value_left, volume_reg_value_right; - - changed = 0; - - cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); - volume_reg_value_left = 255 - (ucontrol->value.integer.value[0] & 0xFF); - volume_reg_value_right = 255 - (ucontrol->value.integer.value[1] & 0xFF); - -#if SND_UBI32_DEBUG - snd_printk(KERN_INFO "Setting volume: writing %d,%d to CS4350 volume registers\n", volume_reg_value_left, volume_reg_value_right); -#endif - spin_lock_irqsave(&cs4350_priv->lock, flags); - - if (cs4350_priv->volume[0] != ucontrol->value.integer.value[0]) { - send[0] = 0x05; // left channel - send[1] = volume_reg_value_left; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); - return changed; - } - cs4350_priv->volume[0] = ucontrol->value.integer.value[0]; - changed = 1; - } - - if (cs4350_priv->volume[1] != ucontrol->value.integer.value[1]) { - send[0] = 0x06; // right channel - send[1] = volume_reg_value_right; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set channel B volume on CS4350\n"); - return changed; - } - cs4350_priv->volume[1] = ucontrol->value.integer.value[1]; - changed = 1; - } - - spin_unlock_irqrestore(&cs4350_priv->lock, flags); - - return changed; -} - -static struct snd_kcontrol_new ubi32_cs4350_volume __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "PCM Playback Volume", - .info = ubi32_cs4350_volume_info, - .get = ubi32_cs4350_volume_get, - .put = ubi32_cs4350_volume_put, - .tlv.p = snd_ubi32_cs4350_db, -}; - -static int ubi32_cs4350_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); - struct ubi32_cs4350_priv *cs4350_priv; - unsigned long flags; - - cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); - - spin_lock_irqsave(&cs4350_priv->lock, flags); - - ucontrol->value.integer.value[0] = cs4350_priv->mute & 1; - ucontrol->value.integer.value[1] = (cs4350_priv->mute & (1 << 1)) ? 1 : 0; - - spin_unlock_irqrestore(&cs4350_priv->lock, flags); - - return 0; -} - -static int ubi32_cs4350_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol); - struct i2c_client *client = (struct i2c_client *)ubi32_priv->client; - struct ubi32_cs4350_priv *cs4350_priv; - unsigned long flags; - int ret, changed; - char send[2]; - char recv[1]; - uint8_t mute; - - changed = 0; - - cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); - - spin_lock_irqsave(&cs4350_priv->lock, flags); - - if ((cs4350_priv->mute & 1) != ucontrol->value.integer.value[0]) { - send[0] = 0x04; - ret = i2c_master_send(client, send, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed to write to mute register: channel 0\n"); - return changed; - } - - ret = i2c_master_recv(client, recv, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed to read mute register: channel 0\n"); - return changed; - } - - mute = recv[0]; - - if (ucontrol->value.integer.value[0]) { - cs4350_priv->mute |= 1; - mute &= ~(1 << 4); -#if SND_UBI32_DEBUG - snd_printk(KERN_INFO "Unmuted channel A\n"); -#endif - } else { - cs4350_priv->mute &= ~1; - mute |= (1 << 4); -#if SND_UBI32_DEBUG - snd_printk(KERN_INFO "Muted channel A\n"); -#endif - } - - send[0] = 0x04; - send[1] = mute; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n"); - return changed; - } - changed = 1; - } - - if (((cs4350_priv->mute & 2) >> 1) != ucontrol->value.integer.value[1]) { - send[0] = 0x04; - ret = i2c_master_send(client, send, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed to write to mute register: channel 1\n"); - return changed; - } - - ret = i2c_master_recv(client, recv, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed to read mute register: channel 1\n"); - return changed; - } - - mute = recv[0]; - - if (ucontrol->value.integer.value[1]) { - cs4350_priv->mute |= (1 << 1); - mute &= ~(1 << 3); -#if SND_UBI32_DEBUG - snd_printk(KERN_INFO "Unmuted channel B\n"); -#endif - } else { - cs4350_priv->mute &= ~(1 << 1); - mute |= (1 << 3); -#if SND_UBI32_DEBUG - snd_printk(KERN_INFO "Muted channel B\n"); -#endif - } - - send[0] = 0x04; - send[1] = mute; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n"); - return changed; - } - changed = 1; - } - - spin_unlock_irqrestore(&cs4350_priv->lock, flags); - - return changed; -} - -static struct snd_kcontrol_new ubi32_cs4350_mute __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .name = "PCM Playback Switch", - .info = ubi32_cs4350_mute_info, - .get = ubi32_cs4350_mute_get, - .put = ubi32_cs4350_mute_put, -}; - -/* - * snd_ubi32_cs4350_free - * Card private data free function - */ -void snd_ubi32_cs4350_free(struct snd_card *card) -{ - struct ubi32_snd_priv *ubi32_priv; - struct ubi32_cs4350_priv *cs4350_priv; - - ubi32_priv = card->private_data; - cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv); - if (cs4350_priv) { - kfree(cs4350_priv); - } -} - -/* - * snd_ubi32_cs4350_dac_init - */ -static int snd_ubi32_cs4350_dac_init(struct i2c_client *client, const struct i2c_device_id *id) -{ - int ret; - char send[2]; - char recv[8]; - - /* - * Initialize the CS4350 DAC over the I2C interface - */ - snd_printk(KERN_INFO "Initializing CS4350 DAC\n"); - - /* - * Register 0x01: device/revid - */ - send[0] = 0x01; - ret = i2c_master_send(client, send, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed 1st attempt to write to CS4350 register 0x01\n"); - goto fail; - } - ret = i2c_master_recv(client, recv, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed initial read of CS4350 registers\n"); - goto fail; - } - snd_printk(KERN_INFO "CS4350 DAC Device/Rev: %08x\n", recv[0]); - - /* - * Register 0x02: Mode control - * I2S DIF[2:0] = 001, no De-Emphasis, Auto speed mode - */ - send[0] = 0x02; - send[1] = 0x10; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set CS4350 to I2S mode\n"); - goto fail; - } - - /* - * Register 0x05/0x06: Volume control - * Channel A volume set to 0 dB - * Channel B volume set to 0 dB - */ - send[0] = 0x05; - send[1] = 0x00; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); - goto fail; - } - - send[0] = 0x06; - send[1] = 0x00; - ret = i2c_master_send(client, send, 2); - if (ret != 2) { - snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n"); - goto fail; - } - - /* - * Make sure the changes took place, this helps verify we are talking to - * the correct chip. - */ - send[0] = 0x81; - ret = i2c_master_send(client, send, 1); - if (ret != 1) { - snd_printk(KERN_ERR "Failed to initiate readback\n"); - goto fail; - } - - ret = i2c_master_recv(client, recv, 8); - if (ret != 8) { - snd_printk(KERN_ERR "Failed second read of CS4350 registers\n"); - goto fail; - } - - if ((recv[1] != 0x10) || (recv[4] != 0x00) || (recv[5] != 0x00)) { - snd_printk(KERN_ERR "Failed to initialize CS4350 DAC\n"); - goto fail; - } - - snd_printk(KERN_INFO "CS4350 DAC Initialized\n"); - return 0; - -fail: - return -ENODEV; -} - -/* - * snd_ubi32_cs4350_i2c_probe - */ -static int snd_ubi32_cs4350_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct snd_card *card; - struct ubi32_snd_priv *ubi32_priv; - struct ubi32_cs4350_priv *cs4350_priv; - int err, ret; - struct platform_device *pdev; - - pdev = client->dev.platform_data; - if (!pdev) { - return -ENODEV; - } - - /* - * Initialize the CS4350 DAC - */ - ret = snd_ubi32_cs4350_dac_init(client, id); - if (ret < 0) { - /* - * Initialization failed. Propagate the error. - */ - return ret; - } - - /* - * Create a snd_card structure - */ - card = snd_card_new(index, "Ubi32-CS4350", THIS_MODULE, sizeof(struct ubi32_snd_priv)); - if (card == NULL) { - return -ENOMEM; - } - - card->private_free = snd_ubi32_cs4350_free; /* Not sure if correct */ - ubi32_priv = card->private_data; - - /* - * CS4350 DAC has a minimum sample rate of 30khz and an - * upper limit of 216khz for it's auto-detect. - */ - ubi32_priv->min_sample_rate = 30000; - ubi32_priv->max_sample_rate = 216000; - - /* - * Initialize the snd_card's private data structure - */ - ubi32_priv->card = card; - ubi32_priv->client = client; - - /* - * Create our private data structure - */ - cs4350_priv = kzalloc(sizeof(struct ubi32_cs4350_priv), GFP_KERNEL); - if (!cs4350_priv) { - snd_card_free(card); - return -ENOMEM; - } - snd_ubi32_priv_set_drv(ubi32_priv, cs4350_priv); - spin_lock_init(&cs4350_priv->lock); - - /* - * Initial volume is set to max by probe function - */ - cs4350_priv->volume[0] = 0xFF; - cs4350_priv->volume[1] = 0xFF; - - /* - * The CS4350 starts off unmuted (bit set = not muted) - */ - cs4350_priv->mute = 3; - - /* - * Create the new PCM instance - */ - err = snd_ubi32_pcm_probe(ubi32_priv, pdev); - if (err < 0) { - snd_card_free(card); - return err; /* What is err? Need to include correct file */ - } - - strcpy(card->driver, "Ubi32-CS4350"); - strcpy(card->shortname, "Ubi32-CS4350"); - snprintf(card->longname, sizeof(card->longname), - "%s at sendirq=%d.%d recvirq=%d.%d regs=%p", - card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx, - ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr); - - snd_card_set_dev(card, &client->dev); - - /* - * Set up the mixer components - */ - err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_volume, ubi32_priv)); - if (err) { - snd_printk(KERN_WARNING "Failed to add volume mixer control\n"); - } - err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_mute, ubi32_priv)); - if (err) { - snd_printk(KERN_WARNING "Failed to add mute mixer control\n"); - } - - /* - * Register the sound card - */ - if ((err = snd_card_register(card)) != 0) { - snd_printk(KERN_WARNING "snd_card_register error\n"); - } - - /* - * Store card for access from other methods - */ - i2c_set_clientdata(client, card); - - return 0; -} - -/* - * snd_ubi32_cs4350_i2c_remove - */ -static int __devexit snd_ubi32_cs4350_i2c_remove(struct i2c_client *client) -{ - struct snd_card *card; - struct ubi32_snd_priv *ubi32_priv; - - card = i2c_get_clientdata(client); - - ubi32_priv = card->private_data; - snd_ubi32_pcm_remove(ubi32_priv); - - snd_card_free(i2c_get_clientdata(client)); - i2c_set_clientdata(client, NULL); - - return 0; -} - -/* - * I2C driver description - */ -static struct i2c_driver snd_ubi32_cs4350_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .id_table = snd_ubi32_cs4350_id, - .probe = snd_ubi32_cs4350_i2c_probe, - .remove = __devexit_p(snd_ubi32_cs4350_i2c_remove), -}; - -/* - * Driver init - */ -static int __init snd_ubi32_cs4350_init(void) -{ - return i2c_add_driver(&snd_ubi32_cs4350_driver); -} -module_init(snd_ubi32_cs4350_init); - -/* - * snd_ubi32_cs4350_exit - */ -static void __exit snd_ubi32_cs4350_exit(void) -{ - i2c_del_driver(&snd_ubi32_cs4350_driver); -} -module_exit(snd_ubi32_cs4350_exit); - -/* - * Module properties - */ -MODULE_ALIAS("i2c:" DRIVER_NAME); -MODULE_AUTHOR("Patrick Tjin"); -MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4350"); -MODULE_LICENSE("GPL"); |