diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/sound/aoa | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/sound/aoa')
33 files changed, 0 insertions, 7711 deletions
diff --git a/ANDROID_3.4.5/sound/aoa/Kconfig b/ANDROID_3.4.5/sound/aoa/Kconfig deleted file mode 100644 index c081e18b..00000000 --- a/ANDROID_3.4.5/sound/aoa/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -menuconfig SND_AOA - tristate "Apple Onboard Audio driver" - depends on PPC_PMAC - select SND_PCM - ---help--- - This option enables the new driver for the various - Apple Onboard Audio components. - -if SND_AOA - -source "sound/aoa/fabrics/Kconfig" - -source "sound/aoa/codecs/Kconfig" - -source "sound/aoa/soundbus/Kconfig" - -endif # SND_AOA diff --git a/ANDROID_3.4.5/sound/aoa/Makefile b/ANDROID_3.4.5/sound/aoa/Makefile deleted file mode 100644 index a8c037f9..00000000 --- a/ANDROID_3.4.5/sound/aoa/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_SND_AOA) += core/ -obj-$(CONFIG_SND_AOA_SOUNDBUS) += soundbus/ -obj-$(CONFIG_SND_AOA) += fabrics/ -obj-$(CONFIG_SND_AOA) += codecs/ diff --git a/ANDROID_3.4.5/sound/aoa/aoa-gpio.h b/ANDROID_3.4.5/sound/aoa/aoa-gpio.h deleted file mode 100644 index 6065b034..00000000 --- a/ANDROID_3.4.5/sound/aoa/aoa-gpio.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Apple Onboard Audio GPIO definitions - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#ifndef __AOA_GPIO_H -#define __AOA_GPIO_H -#include <linux/workqueue.h> -#include <linux/mutex.h> -#include <asm/prom.h> - -typedef void (*notify_func_t)(void *data); - -enum notify_type { - AOA_NOTIFY_HEADPHONE, - AOA_NOTIFY_LINE_IN, - AOA_NOTIFY_LINE_OUT, -}; - -struct gpio_runtime; -struct gpio_methods { - /* for initialisation/de-initialisation of the GPIO layer */ - void (*init)(struct gpio_runtime *rt); - void (*exit)(struct gpio_runtime *rt); - - /* turn off headphone, speakers, lineout */ - void (*all_amps_off)(struct gpio_runtime *rt); - /* turn headphone, speakers, lineout back to previous setting */ - void (*all_amps_restore)(struct gpio_runtime *rt); - - void (*set_headphone)(struct gpio_runtime *rt, int on); - void (*set_speakers)(struct gpio_runtime *rt, int on); - void (*set_lineout)(struct gpio_runtime *rt, int on); - void (*set_master)(struct gpio_runtime *rt, int on); - - int (*get_headphone)(struct gpio_runtime *rt); - int (*get_speakers)(struct gpio_runtime *rt); - int (*get_lineout)(struct gpio_runtime *rt); - int (*get_master)(struct gpio_runtime *rt); - - void (*set_hw_reset)(struct gpio_runtime *rt, int on); - - /* use this to be notified of any events. The notification - * function is passed the data, and is called in process - * context by the use of schedule_work. - * The interface for it is that setting a function to NULL - * removes it, and they return 0 if the operation succeeded, - * and -EBUSY if the notification is already assigned by - * someone else. */ - int (*set_notify)(struct gpio_runtime *rt, - enum notify_type type, - notify_func_t notify, - void *data); - /* returns 0 if not plugged in, 1 if plugged in - * or a negative error code */ - int (*get_detect)(struct gpio_runtime *rt, - enum notify_type type); -}; - -struct gpio_notification { - struct delayed_work work; - notify_func_t notify; - void *data; - void *gpio_private; - struct mutex mutex; -}; - -struct gpio_runtime { - /* to be assigned by fabric */ - struct device_node *node; - /* since everyone needs this pointer anyway... */ - struct gpio_methods *methods; - /* to be used by the gpio implementation */ - int implementation_private; - struct gpio_notification headphone_notify; - struct gpio_notification line_in_notify; - struct gpio_notification line_out_notify; -}; - -#endif /* __AOA_GPIO_H */ diff --git a/ANDROID_3.4.5/sound/aoa/aoa.h b/ANDROID_3.4.5/sound/aoa/aoa.h deleted file mode 100644 index e0878948..00000000 --- a/ANDROID_3.4.5/sound/aoa/aoa.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Apple Onboard Audio definitions - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#ifndef __AOA_H -#define __AOA_H -#include <asm/prom.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/asound.h> -#include <sound/control.h> -#include "aoa-gpio.h" -#include "soundbus/soundbus.h" - -#define MAX_CODEC_NAME_LEN 32 - -struct aoa_codec { - char name[MAX_CODEC_NAME_LEN]; - - struct module *owner; - - /* called when the fabric wants to init this codec. - * Do alsa card manipulations from here. */ - int (*init)(struct aoa_codec *codec); - - /* called when the fabric is done with the codec. - * The alsa card will be cleaned up so don't bother. */ - void (*exit)(struct aoa_codec *codec); - - /* May be NULL, but can be used by the fabric. - * Refcounting is the codec driver's responsibility */ - struct device_node *node; - - /* assigned by fabric before init() is called, points - * to the soundbus device. Cannot be NULL. */ - struct soundbus_dev *soundbus_dev; - - /* assigned by the fabric before init() is called, points - * to the fabric's gpio runtime record for the relevant - * device. */ - struct gpio_runtime *gpio; - - /* assigned by the fabric before init() is called, contains - * a codec specific bitmask of what outputs and inputs are - * actually connected */ - u32 connected; - - /* data the fabric can associate with this structure */ - void *fabric_data; - - /* private! */ - struct list_head list; - struct aoa_fabric *fabric; -}; - -/* return 0 on success */ -extern int -aoa_codec_register(struct aoa_codec *codec); -extern void -aoa_codec_unregister(struct aoa_codec *codec); - -#define MAX_LAYOUT_NAME_LEN 32 - -struct aoa_fabric { - char name[MAX_LAYOUT_NAME_LEN]; - - struct module *owner; - - /* once codecs register, they are passed here after. - * They are of course not initialised, since the - * fabric is responsible for initialising some fields - * in the codec structure! */ - int (*found_codec)(struct aoa_codec *codec); - /* called for each codec when it is removed, - * also in the case that aoa_fabric_unregister - * is called and all codecs are removed - * from this fabric. - * Also called if found_codec returned 0 but - * the codec couldn't initialise. */ - void (*remove_codec)(struct aoa_codec *codec); - /* If found_codec returned 0, and the codec - * could be initialised, this is called. */ - void (*attached_codec)(struct aoa_codec *codec); -}; - -/* return 0 on success, -EEXIST if another fabric is - * registered, -EALREADY if the same fabric is registered. - * Passing NULL can be used to test for the presence - * of another fabric, if -EALREADY is returned there is - * no other fabric present. - * In the case that the function returns -EALREADY - * and the fabric passed is not NULL, all codecs - * that are not assigned yet are passed to the fabric - * again for reconsideration. */ -extern int -aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev); - -/* it is vital to call this when the fabric exits! - * When calling, the remove_codec will be called - * for all codecs, unless it is NULL. */ -extern void -aoa_fabric_unregister(struct aoa_fabric *fabric); - -/* if for some reason you want to get rid of a codec - * before the fabric is removed, use this. - * Note that remove_codec is called for it! */ -extern void -aoa_fabric_unlink_codec(struct aoa_codec *codec); - -/* alsa help methods */ -struct aoa_card { - struct snd_card *alsa_card; -}; - -extern int aoa_snd_device_new(snd_device_type_t type, - void * device_data, struct snd_device_ops * ops); -extern struct snd_card *aoa_get_card(void); -extern int aoa_snd_ctl_add(struct snd_kcontrol* control); - -/* GPIO stuff */ -extern struct gpio_methods *pmf_gpio_methods; -extern struct gpio_methods *ftr_gpio_methods; -/* extern struct gpio_methods *map_gpio_methods; */ - -#endif /* __AOA_H */ diff --git a/ANDROID_3.4.5/sound/aoa/codecs/Kconfig b/ANDROID_3.4.5/sound/aoa/codecs/Kconfig deleted file mode 100644 index 0c68e328..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config SND_AOA_ONYX - tristate "support Onyx chip" - select I2C - select I2C_POWERMAC - ---help--- - This option enables support for the Onyx (pcm3052) - codec chip found in the latest Apple machines - (most of those with digital audio output). - -config SND_AOA_TAS - tristate "support TAS chips" - select I2C - select I2C_POWERMAC - ---help--- - This option enables support for the tas chips - found in a lot of Apple Machines, especially - iBooks and PowerBooks without digital. - -config SND_AOA_TOONIE - tristate "support Toonie chip" - ---help--- - This option enables support for the toonie codec - found in the Mac Mini. If you have a Mac Mini and - want to hear sound, select this option. diff --git a/ANDROID_3.4.5/sound/aoa/codecs/Makefile b/ANDROID_3.4.5/sound/aoa/codecs/Makefile deleted file mode 100644 index c3ee77fc..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -snd-aoa-codec-onyx-objs := onyx.o -snd-aoa-codec-tas-objs := tas.o -snd-aoa-codec-toonie-objs := toonie.o - -obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o -obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o -obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o diff --git a/ANDROID_3.4.5/sound/aoa/codecs/onyx.c b/ANDROID_3.4.5/sound/aoa/codecs/onyx.c deleted file mode 100644 index 270790d3..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/onyx.c +++ /dev/null @@ -1,1135 +0,0 @@ -/* - * Apple Onboard Audio driver for Onyx codec - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - * - * - * This is a driver for the pcm3052 codec chip (codenamed Onyx) - * that is present in newer Apple hardware (with digital output). - * - * The Onyx codec has the following connections (listed by the bit - * to be used in aoa_codec.connected): - * 0: analog output - * 1: digital output - * 2: line input - * 3: microphone input - * Note that even though I know of no machine that has for example - * the digital output connected but not the analog, I have handled - * all the different cases in the code so that this driver may serve - * as a good example of what to do. - * - * NOTE: This driver assumes that there's at most one chip to be - * used with one alsa card, in form of creating all kinds - * of mixer elements without regard for their existence. - * But snd-aoa assumes that there's at most one card, so - * this means you can only have one onyx on a system. This - * should probably be fixed by changing the assumption of - * having just a single card on a system, and making the - * 'card' pointer accessible to anyone who needs it instead - * of hiding it in the aoa_snd_* functions... - * - */ -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/slab.h> -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa"); - -#include "onyx.h" -#include "../aoa.h" -#include "../soundbus/soundbus.h" - - -#define PFX "snd-aoa-codec-onyx: " - -struct onyx { - /* cache registers 65 to 80, they are write-only! */ - u8 cache[16]; - struct i2c_client *i2c; - struct aoa_codec codec; - u32 initialised:1, - spdif_locked:1, - analog_locked:1, - original_mute:2; - int open_count; - struct codec_info *codec_info; - - /* mutex serializes concurrent access to the device - * and this structure. - */ - struct mutex mutex; -}; -#define codec_to_onyx(c) container_of(c, struct onyx, codec) - -/* both return 0 if all ok, else on error */ -static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value) -{ - s32 v; - - if (reg != ONYX_REG_CONTROL) { - *value = onyx->cache[reg-FIRSTREGISTER]; - return 0; - } - v = i2c_smbus_read_byte_data(onyx->i2c, reg); - if (v < 0) - return -1; - *value = (u8)v; - onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; - return 0; -} - -static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value) -{ - int result; - - result = i2c_smbus_write_byte_data(onyx->i2c, reg, value); - if (!result) - onyx->cache[reg-FIRSTREGISTER] = value; - return result; -} - -/* alsa stuff */ - -static int onyx_dev_register(struct snd_device *dev) -{ - return 0; -} - -static struct snd_device_ops ops = { - .dev_register = onyx_dev_register, -}; - -/* this is necessary because most alsa mixer programs - * can't properly handle the negative range */ -#define VOLUME_RANGE_SHIFT 128 - -static int onyx_snd_vol_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 = -128 + VOLUME_RANGE_SHIFT; - uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT; - return 0; -} - -static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - s8 l, r; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); - onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); - mutex_unlock(&onyx->mutex); - - ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT; - ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT; - - return 0; -} - -static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - s8 l, r; - - if (ucontrol->value.integer.value[0] < -128 + VOLUME_RANGE_SHIFT || - ucontrol->value.integer.value[0] > -1 + VOLUME_RANGE_SHIFT) - return -EINVAL; - if (ucontrol->value.integer.value[1] < -128 + VOLUME_RANGE_SHIFT || - ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT) - return -EINVAL; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); - onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); - - if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] && - r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) { - mutex_unlock(&onyx->mutex); - return 0; - } - - onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, - ucontrol->value.integer.value[0] - - VOLUME_RANGE_SHIFT); - onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, - ucontrol->value.integer.value[1] - - VOLUME_RANGE_SHIFT); - mutex_unlock(&onyx->mutex); - - return 1; -} - -static struct snd_kcontrol_new volume_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = onyx_snd_vol_info, - .get = onyx_snd_vol_get, - .put = onyx_snd_vol_put, -}; - -/* like above, this is necessary because a lot - * of alsa mixer programs don't handle ranges - * that don't start at 0 properly. - * even alsamixer is one of them... */ -#define INPUTGAIN_RANGE_SHIFT (-3) - -static int onyx_snd_inputgain_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT; - uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT; - return 0; -} - -static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 ig; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig); - mutex_unlock(&onyx->mutex); - - ucontrol->value.integer.value[0] = - (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT; - - return 0; -} - -static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 v, n; - - if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT || - ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT) - return -EINVAL; - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); - n = v; - n &= ~ONYX_ADC_PGA_GAIN_MASK; - n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT) - & ONYX_ADC_PGA_GAIN_MASK; - onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n); - mutex_unlock(&onyx->mutex); - - return n != v; -} - -static struct snd_kcontrol_new inputgain_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = onyx_snd_inputgain_info, - .get = onyx_snd_inputgain_get, - .put = onyx_snd_inputgain_put, -}; - -static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { "Line-In", "Microphone" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - s8 v; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); - mutex_unlock(&onyx->mutex); - - ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC); - - return 0; -} - -static void onyx_set_capture_source(struct onyx *onyx, int mic) -{ - s8 v; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); - v &= ~ONYX_ADC_INPUT_MIC; - if (mic) - v |= ONYX_ADC_INPUT_MIC; - onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v); - mutex_unlock(&onyx->mutex); -} - -static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - if (ucontrol->value.enumerated.item[0] > 1) - return -EINVAL; - onyx_set_capture_source(snd_kcontrol_chip(kcontrol), - ucontrol->value.enumerated.item[0]); - return 1; -} - -static struct snd_kcontrol_new capture_source_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* If we name this 'Input Source', it properly shows up in - * alsamixer as a selection, * but it's shown under the - * 'Playback' category. - * If I name it 'Capture Source', it shows up in strange - * ways (two bools of which one can be selected at a - * time) but at least it's shown in the 'Capture' - * category. - * I was told that this was due to backward compatibility, - * but I don't understand then why the mangling is *not* - * done when I name it "Input Source"..... - */ - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = onyx_snd_capture_source_info, - .get = onyx_snd_capture_source_get, - .put = onyx_snd_capture_source_put, -}; - -#define onyx_snd_mute_info snd_ctl_boolean_stereo_info - -static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 c; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c); - mutex_unlock(&onyx->mutex); - - ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT); - ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT); - - return 0; -} - -static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 v = 0, c = 0; - int err = -EBUSY; - - mutex_lock(&onyx->mutex); - if (onyx->analog_locked) - goto out_unlock; - - onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); - c = v; - c &= ~(ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT); - if (!ucontrol->value.integer.value[0]) - c |= ONYX_MUTE_LEFT; - if (!ucontrol->value.integer.value[1]) - c |= ONYX_MUTE_RIGHT; - err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c); - - out_unlock: - mutex_unlock(&onyx->mutex); - - return !err ? (v != c) : err; -} - -static struct snd_kcontrol_new mute_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = onyx_snd_mute_info, - .get = onyx_snd_mute_get, - .put = onyx_snd_mute_put, -}; - - -#define onyx_snd_single_bit_info snd_ctl_boolean_mono_info - -#define FLAG_POLARITY_INVERT 1 -#define FLAG_SPDIFLOCK 2 - -static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 c; - long int pv = kcontrol->private_value; - u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT; - u8 address = (pv >> 8) & 0xff; - u8 mask = pv & 0xff; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, address, &c); - mutex_unlock(&onyx->mutex); - - ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity; - - return 0; -} - -static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 v = 0, c = 0; - int err; - long int pv = kcontrol->private_value; - u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT; - u8 spdiflock = (pv >> 16) & FLAG_SPDIFLOCK; - u8 address = (pv >> 8) & 0xff; - u8 mask = pv & 0xff; - - mutex_lock(&onyx->mutex); - if (spdiflock && onyx->spdif_locked) { - /* even if alsamixer doesn't care.. */ - err = -EBUSY; - goto out_unlock; - } - onyx_read_register(onyx, address, &v); - c = v; - c &= ~(mask); - if (!!ucontrol->value.integer.value[0] ^ polarity) - c |= mask; - err = onyx_write_register(onyx, address, c); - - out_unlock: - mutex_unlock(&onyx->mutex); - - return !err ? (v != c) : err; -} - -#define SINGLE_BIT(n, type, description, address, mask, flags) \ -static struct snd_kcontrol_new n##_control = { \ - .iface = SNDRV_CTL_ELEM_IFACE_##type, \ - .name = description, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = onyx_snd_single_bit_info, \ - .get = onyx_snd_single_bit_get, \ - .put = onyx_snd_single_bit_put, \ - .private_value = (flags << 16) | (address << 8) | mask \ -} - -SINGLE_BIT(spdif, - MIXER, - SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), - ONYX_REG_DIG_INFO4, - ONYX_SPDIF_ENABLE, - FLAG_SPDIFLOCK); -SINGLE_BIT(ovr1, - MIXER, - "Oversampling Rate", - ONYX_REG_DAC_CONTROL, - ONYX_OVR1, - 0); -SINGLE_BIT(flt0, - MIXER, - "Fast Digital Filter Rolloff", - ONYX_REG_DAC_FILTER, - ONYX_ROLLOFF_FAST, - FLAG_POLARITY_INVERT); -SINGLE_BIT(hpf, - MIXER, - "Highpass Filter", - ONYX_REG_ADC_HPF_BYPASS, - ONYX_HPF_DISABLE, - FLAG_POLARITY_INVERT); -SINGLE_BIT(dm12, - MIXER, - "Digital De-Emphasis", - ONYX_REG_DAC_DEEMPH, - ONYX_DIGDEEMPH_CTRL, - 0); - -static int onyx_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; - uinfo->count = 1; - return 0; -} - -static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - /* datasheet page 30, all others are 0 */ - ucontrol->value.iec958.status[0] = 0x3e; - ucontrol->value.iec958.status[1] = 0xff; - - ucontrol->value.iec958.status[3] = 0x3f; - ucontrol->value.iec958.status[4] = 0x0f; - - return 0; -} - -static struct snd_kcontrol_new onyx_spdif_mask = { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), - .info = onyx_spdif_info, - .get = onyx_spdif_mask_get, -}; - -static int onyx_spdif_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 v; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v); - ucontrol->value.iec958.status[0] = v & 0x3e; - - onyx_read_register(onyx, ONYX_REG_DIG_INFO2, &v); - ucontrol->value.iec958.status[1] = v; - - onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v); - ucontrol->value.iec958.status[3] = v & 0x3f; - - onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); - ucontrol->value.iec958.status[4] = v & 0x0f; - mutex_unlock(&onyx->mutex); - - return 0; -} - -static int onyx_spdif_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct onyx *onyx = snd_kcontrol_chip(kcontrol); - u8 v; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v); - v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e); - onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v); - - v = ucontrol->value.iec958.status[1]; - onyx_write_register(onyx, ONYX_REG_DIG_INFO2, v); - - onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v); - v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f); - onyx_write_register(onyx, ONYX_REG_DIG_INFO3, v); - - onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); - v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f); - onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v); - mutex_unlock(&onyx->mutex); - - return 1; -} - -static struct snd_kcontrol_new onyx_spdif_ctrl = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), - .info = onyx_spdif_info, - .get = onyx_spdif_get, - .put = onyx_spdif_put, -}; - -/* our registers */ - -static u8 register_map[] = { - ONYX_REG_DAC_ATTEN_LEFT, - ONYX_REG_DAC_ATTEN_RIGHT, - ONYX_REG_CONTROL, - ONYX_REG_DAC_CONTROL, - ONYX_REG_DAC_DEEMPH, - ONYX_REG_DAC_FILTER, - ONYX_REG_DAC_OUTPHASE, - ONYX_REG_ADC_CONTROL, - ONYX_REG_ADC_HPF_BYPASS, - ONYX_REG_DIG_INFO1, - ONYX_REG_DIG_INFO2, - ONYX_REG_DIG_INFO3, - ONYX_REG_DIG_INFO4 -}; - -static u8 initial_values[ARRAY_SIZE(register_map)] = { - 0x80, 0x80, /* muted */ - ONYX_MRST | ONYX_SRST, /* but handled specially! */ - ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT, - 0, /* no deemphasis */ - ONYX_DAC_FILTER_ALWAYS, - ONYX_OUTPHASE_INVERTED, - (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/ - ONYX_ADC_HPF_ALWAYS, - (1<<2), /* pcm audio */ - 2, /* category: pcm coder */ - 0, /* sampling frequency 44.1 kHz, clock accuracy level II */ - 1 /* 24 bit depth */ -}; - -/* reset registers of chip, either to initial or to previous values */ -static int onyx_register_init(struct onyx *onyx) -{ - int i; - u8 val; - u8 regs[sizeof(initial_values)]; - - if (!onyx->initialised) { - memcpy(regs, initial_values, sizeof(initial_values)); - if (onyx_read_register(onyx, ONYX_REG_CONTROL, &val)) - return -1; - val &= ~ONYX_SILICONVERSION; - val |= initial_values[3]; - regs[3] = val; - } else { - for (i=0; i<sizeof(register_map); i++) - regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER]; - } - - for (i=0; i<sizeof(register_map); i++) { - if (onyx_write_register(onyx, register_map[i], regs[i])) - return -1; - } - onyx->initialised = 1; - return 0; -} - -static struct transfer_info onyx_transfers[] = { - /* this is first so we can skip it if no input is present... - * No hardware exists with that, but it's here as an example - * of what to do :) */ - { - /* analog input */ - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE, - .rates = SNDRV_PCM_RATE_8000_96000, - .transfer_in = 1, - .must_be_clock_source = 0, - .tag = 0, - }, - { - /* if analog and digital are currently off, anything should go, - * so this entry describes everything we can do... */ - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE -#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE - | SNDRV_PCM_FMTBIT_COMPRESSED_16BE -#endif - , - .rates = SNDRV_PCM_RATE_8000_96000, - .tag = 0, - }, - { - /* analog output */ - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE, - .rates = SNDRV_PCM_RATE_8000_96000, - .transfer_in = 0, - .must_be_clock_source = 0, - .tag = 1, - }, - { - /* digital pcm output, also possible for analog out */ - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, - .transfer_in = 0, - .must_be_clock_source = 0, - .tag = 2, - }, -#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE - /* Once alsa gets supports for this kind of thing we can add it... */ - { - /* digital compressed output */ - .formats = SNDRV_PCM_FMTBIT_COMPRESSED_16BE, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, - .tag = 2, - }, -#endif - {} -}; - -static int onyx_usable(struct codec_info_item *cii, - struct transfer_info *ti, - struct transfer_info *out) -{ - u8 v; - struct onyx *onyx = cii->codec_data; - int spdif_enabled, analog_enabled; - - mutex_lock(&onyx->mutex); - onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); - spdif_enabled = !!(v & ONYX_SPDIF_ENABLE); - onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); - analog_enabled = - (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT)) - != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT); - mutex_unlock(&onyx->mutex); - - switch (ti->tag) { - case 0: return 1; - case 1: return analog_enabled; - case 2: return spdif_enabled; - } - return 1; -} - -static int onyx_prepare(struct codec_info_item *cii, - struct bus_info *bi, - struct snd_pcm_substream *substream) -{ - u8 v; - struct onyx *onyx = cii->codec_data; - int err = -EBUSY; - - mutex_lock(&onyx->mutex); - -#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE - if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) { - /* mute and lock analog output */ - onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); - if (onyx_write_register(onyx, - ONYX_REG_DAC_CONTROL, - v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT)) - goto out_unlock; - onyx->analog_locked = 1; - err = 0; - goto out_unlock; - } -#endif - switch (substream->runtime->rate) { - case 32000: - case 44100: - case 48000: - /* these rates are ok for all outputs */ - /* FIXME: program spdif channel control bits here so that - * userspace doesn't have to if it only plays pcm! */ - err = 0; - goto out_unlock; - default: - /* got some rate that the digital output can't do, - * so disable and lock it */ - onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v); - if (onyx_write_register(onyx, - ONYX_REG_DIG_INFO4, - v & ~ONYX_SPDIF_ENABLE)) - goto out_unlock; - onyx->spdif_locked = 1; - err = 0; - goto out_unlock; - } - - out_unlock: - mutex_unlock(&onyx->mutex); - - return err; -} - -static int onyx_open(struct codec_info_item *cii, - struct snd_pcm_substream *substream) -{ - struct onyx *onyx = cii->codec_data; - - mutex_lock(&onyx->mutex); - onyx->open_count++; - mutex_unlock(&onyx->mutex); - - return 0; -} - -static int onyx_close(struct codec_info_item *cii, - struct snd_pcm_substream *substream) -{ - struct onyx *onyx = cii->codec_data; - - mutex_lock(&onyx->mutex); - onyx->open_count--; - if (!onyx->open_count) - onyx->spdif_locked = onyx->analog_locked = 0; - mutex_unlock(&onyx->mutex); - - return 0; -} - -static int onyx_switch_clock(struct codec_info_item *cii, - enum clock_switch what) -{ - struct onyx *onyx = cii->codec_data; - - mutex_lock(&onyx->mutex); - /* this *MUST* be more elaborate later... */ - switch (what) { - case CLOCK_SWITCH_PREPARE_SLAVE: - onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio); - break; - case CLOCK_SWITCH_SLAVE: - onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio); - break; - default: /* silence warning */ - break; - } - mutex_unlock(&onyx->mutex); - - return 0; -} - -#ifdef CONFIG_PM - -static int onyx_suspend(struct codec_info_item *cii, pm_message_t state) -{ - struct onyx *onyx = cii->codec_data; - u8 v; - int err = -ENXIO; - - mutex_lock(&onyx->mutex); - if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) - goto out_unlock; - onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV); - /* Apple does a sleep here but the datasheet says to do it on resume */ - err = 0; - out_unlock: - mutex_unlock(&onyx->mutex); - - return err; -} - -static int onyx_resume(struct codec_info_item *cii) -{ - struct onyx *onyx = cii->codec_data; - u8 v; - int err = -ENXIO; - - mutex_lock(&onyx->mutex); - - /* reset codec */ - onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); - msleep(1); - onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); - msleep(1); - onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); - msleep(1); - - /* take codec out of suspend (if it still is after reset) */ - if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) - goto out_unlock; - onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); - /* FIXME: should divide by sample rate, but 8k is the lowest we go */ - msleep(2205000/8000); - /* reset all values */ - onyx_register_init(onyx); - err = 0; - out_unlock: - mutex_unlock(&onyx->mutex); - - return err; -} - -#endif /* CONFIG_PM */ - -static struct codec_info onyx_codec_info = { - .transfers = onyx_transfers, - .sysclock_factor = 256, - .bus_factor = 64, - .owner = THIS_MODULE, - .usable = onyx_usable, - .prepare = onyx_prepare, - .open = onyx_open, - .close = onyx_close, - .switch_clock = onyx_switch_clock, -#ifdef CONFIG_PM - .suspend = onyx_suspend, - .resume = onyx_resume, -#endif -}; - -static int onyx_init_codec(struct aoa_codec *codec) -{ - struct onyx *onyx = codec_to_onyx(codec); - struct snd_kcontrol *ctl; - struct codec_info *ci = &onyx_codec_info; - u8 v; - int err; - - if (!onyx->codec.gpio || !onyx->codec.gpio->methods) { - printk(KERN_ERR PFX "gpios not assigned!!\n"); - return -EINVAL; - } - - onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); - msleep(1); - onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); - msleep(1); - onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); - msleep(1); - - if (onyx_register_init(onyx)) { - printk(KERN_ERR PFX "failed to initialise onyx registers\n"); - return -ENODEV; - } - - if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) { - printk(KERN_ERR PFX "failed to create onyx snd device!\n"); - return -ENODEV; - } - - /* nothing connected? what a joke! */ - if ((onyx->codec.connected & 0xF) == 0) - return -ENOTCONN; - - /* if no inputs are present... */ - if ((onyx->codec.connected & 0xC) == 0) { - if (!onyx->codec_info) - onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); - if (!onyx->codec_info) - return -ENOMEM; - ci = onyx->codec_info; - *ci = onyx_codec_info; - ci->transfers++; - } - - /* if no outputs are present... */ - if ((onyx->codec.connected & 3) == 0) { - if (!onyx->codec_info) - onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); - if (!onyx->codec_info) - return -ENOMEM; - ci = onyx->codec_info; - /* this is fine as there have to be inputs - * if we end up in this part of the code */ - *ci = onyx_codec_info; - ci->transfers[1].formats = 0; - } - - if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev, - aoa_get_card(), - ci, onyx)) { - printk(KERN_ERR PFX "error creating onyx pcm\n"); - return -ENODEV; - } -#define ADDCTL(n) \ - do { \ - ctl = snd_ctl_new1(&n, onyx); \ - if (ctl) { \ - ctl->id.device = \ - onyx->codec.soundbus_dev->pcm->device; \ - err = aoa_snd_ctl_add(ctl); \ - if (err) \ - goto error; \ - } \ - } while (0) - - if (onyx->codec.soundbus_dev->pcm) { - /* give the user appropriate controls - * depending on what inputs are connected */ - if ((onyx->codec.connected & 0xC) == 0xC) - ADDCTL(capture_source_control); - else if (onyx->codec.connected & 4) - onyx_set_capture_source(onyx, 0); - else - onyx_set_capture_source(onyx, 1); - if (onyx->codec.connected & 0xC) - ADDCTL(inputgain_control); - - /* depending on what output is connected, - * give the user appropriate controls */ - if (onyx->codec.connected & 1) { - ADDCTL(volume_control); - ADDCTL(mute_control); - ADDCTL(ovr1_control); - ADDCTL(flt0_control); - ADDCTL(hpf_control); - ADDCTL(dm12_control); - /* spdif control defaults to off */ - } - if (onyx->codec.connected & 2) { - ADDCTL(onyx_spdif_mask); - ADDCTL(onyx_spdif_ctrl); - } - if ((onyx->codec.connected & 3) == 3) - ADDCTL(spdif_control); - /* if only S/PDIF is connected, enable it unconditionally */ - if ((onyx->codec.connected & 3) == 2) { - onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); - v |= ONYX_SPDIF_ENABLE; - onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v); - } - } -#undef ADDCTL - printk(KERN_INFO PFX "attached to onyx codec via i2c\n"); - - return 0; - error: - onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); - snd_device_free(aoa_get_card(), onyx); - return err; -} - -static void onyx_exit_codec(struct aoa_codec *codec) -{ - struct onyx *onyx = codec_to_onyx(codec); - - if (!onyx->codec.soundbus_dev) { - printk(KERN_ERR PFX "onyx_exit_codec called without soundbus_dev!\n"); - return; - } - onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); -} - -static int onyx_create(struct i2c_adapter *adapter, - struct device_node *node, - int addr) -{ - struct i2c_board_info info; - struct i2c_client *client; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "aoa_codec_onyx", I2C_NAME_SIZE); - info.addr = addr; - info.platform_data = node; - client = i2c_new_device(adapter, &info); - if (!client) - return -ENODEV; - - /* - * We know the driver is already loaded, so the device should be - * already bound. If not it means binding failed, which suggests - * the device doesn't really exist and should be deleted. - * Ideally this would be replaced by better checks _before_ - * instantiating the device. - */ - if (!client->driver) { - i2c_unregister_device(client); - return -ENODEV; - } - - /* - * Let i2c-core delete that device on driver removal. - * This is safe because i2c-core holds the core_lock mutex for us. - */ - list_add_tail(&client->detected, &client->driver->clients); - return 0; -} - -static int onyx_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device_node *node = client->dev.platform_data; - struct onyx *onyx; - u8 dummy; - - onyx = kzalloc(sizeof(struct onyx), GFP_KERNEL); - - if (!onyx) - return -ENOMEM; - - mutex_init(&onyx->mutex); - onyx->i2c = client; - i2c_set_clientdata(client, onyx); - - /* we try to read from register ONYX_REG_CONTROL - * to check if the codec is present */ - if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) { - printk(KERN_ERR PFX "failed to read control register\n"); - goto fail; - } - - strlcpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN); - onyx->codec.owner = THIS_MODULE; - onyx->codec.init = onyx_init_codec; - onyx->codec.exit = onyx_exit_codec; - onyx->codec.node = of_node_get(node); - - if (aoa_codec_register(&onyx->codec)) { - goto fail; - } - printk(KERN_DEBUG PFX "created and attached onyx instance\n"); - return 0; - fail: - kfree(onyx); - return -ENODEV; -} - -static int onyx_i2c_attach(struct i2c_adapter *adapter) -{ - struct device_node *busnode, *dev = NULL; - struct pmac_i2c_bus *bus; - - bus = pmac_i2c_adapter_to_bus(adapter); - if (bus == NULL) - return -ENODEV; - busnode = pmac_i2c_get_bus_node(bus); - - while ((dev = of_get_next_child(busnode, dev)) != NULL) { - if (of_device_is_compatible(dev, "pcm3052")) { - const u32 *addr; - printk(KERN_DEBUG PFX "found pcm3052\n"); - addr = of_get_property(dev, "reg", NULL); - if (!addr) - return -ENODEV; - return onyx_create(adapter, dev, (*addr)>>1); - } - } - - /* if that didn't work, try desperate mode for older - * machines that have stuff missing from the device tree */ - - if (!of_device_is_compatible(busnode, "k2-i2c")) - return -ENODEV; - - printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n"); - /* probe both possible addresses for the onyx chip */ - if (onyx_create(adapter, NULL, 0x46) == 0) - return 0; - return onyx_create(adapter, NULL, 0x47); -} - -static int onyx_i2c_remove(struct i2c_client *client) -{ - struct onyx *onyx = i2c_get_clientdata(client); - - aoa_codec_unregister(&onyx->codec); - of_node_put(onyx->codec.node); - kfree(onyx->codec_info); - kfree(onyx); - return 0; -} - -static const struct i2c_device_id onyx_i2c_id[] = { - { "aoa_codec_onyx", 0 }, - { } -}; - -static struct i2c_driver onyx_driver = { - .driver = { - .name = "aoa_codec_onyx", - .owner = THIS_MODULE, - }, - .attach_adapter = onyx_i2c_attach, - .probe = onyx_i2c_probe, - .remove = onyx_i2c_remove, - .id_table = onyx_i2c_id, -}; - -module_i2c_driver(onyx_driver); diff --git a/ANDROID_3.4.5/sound/aoa/codecs/onyx.h b/ANDROID_3.4.5/sound/aoa/codecs/onyx.h deleted file mode 100644 index ffd20254..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/onyx.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Apple Onboard Audio driver for Onyx codec (header) - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ -#ifndef __SND_AOA_CODEC_ONYX_H -#define __SND_AOA_CODEC_ONYX_H -#include <stddef.h> -#include <linux/i2c.h> -#include <asm/pmac_low_i2c.h> -#include <asm/prom.h> - -/* PCM3052 register definitions */ - -/* the attenuation registers take values from - * -1 (0dB) to -127 (-63.0 dB) or others (muted) */ -#define ONYX_REG_DAC_ATTEN_LEFT 65 -#define FIRSTREGISTER ONYX_REG_DAC_ATTEN_LEFT -#define ONYX_REG_DAC_ATTEN_RIGHT 66 - -#define ONYX_REG_CONTROL 67 -# define ONYX_MRST (1<<7) -# define ONYX_SRST (1<<6) -# define ONYX_ADPSV (1<<5) -# define ONYX_DAPSV (1<<4) -# define ONYX_SILICONVERSION (1<<0) -/* all others reserved */ - -#define ONYX_REG_DAC_CONTROL 68 -# define ONYX_OVR1 (1<<6) -# define ONYX_MUTE_RIGHT (1<<1) -# define ONYX_MUTE_LEFT (1<<0) - -#define ONYX_REG_DAC_DEEMPH 69 -# define ONYX_DIGDEEMPH_SHIFT 5 -# define ONYX_DIGDEEMPH_MASK (3<<ONYX_DIGDEEMPH_SHIFT) -# define ONYX_DIGDEEMPH_CTRL (1<<4) - -#define ONYX_REG_DAC_FILTER 70 -# define ONYX_ROLLOFF_FAST (1<<5) -# define ONYX_DAC_FILTER_ALWAYS (1<<2) - -#define ONYX_REG_DAC_OUTPHASE 71 -# define ONYX_OUTPHASE_INVERTED (1<<0) - -#define ONYX_REG_ADC_CONTROL 72 -# define ONYX_ADC_INPUT_MIC (1<<5) -/* 8 + input gain in dB, valid range for input gain is -4 .. 20 dB */ -# define ONYX_ADC_PGA_GAIN_MASK 0x1f - -#define ONYX_REG_ADC_HPF_BYPASS 75 -# define ONYX_HPF_DISABLE (1<<3) -# define ONYX_ADC_HPF_ALWAYS (1<<2) - -#define ONYX_REG_DIG_INFO1 77 -# define ONYX_MASK_DIN_TO_BPZ (1<<7) -/* bits 1-5 control channel bits 1-5 */ -# define ONYX_DIGOUT_DISABLE (1<<0) - -#define ONYX_REG_DIG_INFO2 78 -/* controls channel bits 8-15 */ - -#define ONYX_REG_DIG_INFO3 79 -/* control channel bits 24-29, high 2 bits reserved */ - -#define ONYX_REG_DIG_INFO4 80 -# define ONYX_VALIDL (1<<7) -# define ONYX_VALIDR (1<<6) -# define ONYX_SPDIF_ENABLE (1<<5) -/* lower 4 bits control bits 32-35 of channel control and word length */ -# define ONYX_WORDLEN_MASK (0xF) - -#endif /* __SND_AOA_CODEC_ONYX_H */ diff --git a/ANDROID_3.4.5/sound/aoa/codecs/tas-basstreble.h b/ANDROID_3.4.5/sound/aoa/codecs/tas-basstreble.h deleted file mode 100644 index 69b61136..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/tas-basstreble.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This file is only included exactly once! - * - * The tables here are derived from the tas3004 datasheet, - * modulo typo corrections and some smoothing... - */ - -#define TAS3004_TREBLE_MIN 0 -#define TAS3004_TREBLE_MAX 72 -#define TAS3004_BASS_MIN 0 -#define TAS3004_BASS_MAX 72 -#define TAS3004_TREBLE_ZERO 36 -#define TAS3004_BASS_ZERO 36 - -static u8 tas3004_treble_table[] = { - 150, /* -18 dB */ - 149, - 148, - 147, - 146, - 145, - 144, - 143, - 142, - 141, - 140, - 139, - 138, - 137, - 136, - 135, - 134, - 133, - 132, - 131, - 130, - 129, - 128, - 127, - 126, - 125, - 124, - 123, - 122, - 121, - 120, - 119, - 118, - 117, - 116, - 115, - 114, /* 0 dB */ - 113, - 112, - 111, - 109, - 108, - 107, - 105, - 104, - 103, - 101, - 99, - 98, - 96, - 93, - 91, - 89, - 86, - 83, - 81, - 77, - 74, - 71, - 67, - 63, - 59, - 54, - 49, - 44, - 38, - 32, - 26, - 19, - 10, - 4, - 2, - 1, /* +18 dB */ -}; - -static inline u8 tas3004_treble(int idx) -{ - return tas3004_treble_table[idx]; -} - -/* I only save the difference here to the treble table - * so that the binary is smaller... - * I have also ignored completely differences of - * +/- 1 - */ -static s8 tas3004_bass_diff_to_treble[] = { - 2, /* 7 dB, offset 50 */ - 2, - 2, - 2, - 2, - 1, - 2, - 2, - 2, - 3, - 4, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 14, - 13, - 8, - 1, /* 18 dB */ -}; - -static inline u8 tas3004_bass(int idx) -{ - u8 result = tas3004_treble_table[idx]; - - if (idx >= 50) - result += tas3004_bass_diff_to_treble[idx-50]; - return result; -} diff --git a/ANDROID_3.4.5/sound/aoa/codecs/tas-gain-table.h b/ANDROID_3.4.5/sound/aoa/codecs/tas-gain-table.h deleted file mode 100644 index 4cfa6757..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/tas-gain-table.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - This is the program used to generate below table. - -#include <stdio.h> -#include <math.h> -int main() { - int dB2; - printf("/" "* This file is only included exactly once!\n"); - printf(" *\n"); - printf(" * If they'd only tell us that generating this table was\n"); - printf(" * as easy as calculating\n"); - printf(" * hwvalue = 1048576.0*exp(0.057564628*dB*2)\n"); - printf(" * :) *" "/\n"); - printf("static int tas_gaintable[] = {\n"); - printf(" 0x000000, /" "* -infinity dB *" "/\n"); - for (dB2=-140;dB2<=36;dB2++) - printf(" 0x%.6x, /" "* %-02.1f dB *" "/\n", (int)(1048576.0*exp(0.057564628*dB2)), dB2/2.0); - printf("};\n\n"); -} - -*/ - -/* This file is only included exactly once! - * - * If they'd only tell us that generating this table was - * as easy as calculating - * hwvalue = 1048576.0*exp(0.057564628*dB*2) - * :) */ -static int tas_gaintable[] = { - 0x000000, /* -infinity dB */ - 0x00014b, /* -70.0 dB */ - 0x00015f, /* -69.5 dB */ - 0x000174, /* -69.0 dB */ - 0x00018a, /* -68.5 dB */ - 0x0001a1, /* -68.0 dB */ - 0x0001ba, /* -67.5 dB */ - 0x0001d4, /* -67.0 dB */ - 0x0001f0, /* -66.5 dB */ - 0x00020d, /* -66.0 dB */ - 0x00022c, /* -65.5 dB */ - 0x00024d, /* -65.0 dB */ - 0x000270, /* -64.5 dB */ - 0x000295, /* -64.0 dB */ - 0x0002bc, /* -63.5 dB */ - 0x0002e6, /* -63.0 dB */ - 0x000312, /* -62.5 dB */ - 0x000340, /* -62.0 dB */ - 0x000372, /* -61.5 dB */ - 0x0003a6, /* -61.0 dB */ - 0x0003dd, /* -60.5 dB */ - 0x000418, /* -60.0 dB */ - 0x000456, /* -59.5 dB */ - 0x000498, /* -59.0 dB */ - 0x0004de, /* -58.5 dB */ - 0x000528, /* -58.0 dB */ - 0x000576, /* -57.5 dB */ - 0x0005c9, /* -57.0 dB */ - 0x000620, /* -56.5 dB */ - 0x00067d, /* -56.0 dB */ - 0x0006e0, /* -55.5 dB */ - 0x000748, /* -55.0 dB */ - 0x0007b7, /* -54.5 dB */ - 0x00082c, /* -54.0 dB */ - 0x0008a8, /* -53.5 dB */ - 0x00092b, /* -53.0 dB */ - 0x0009b6, /* -52.5 dB */ - 0x000a49, /* -52.0 dB */ - 0x000ae5, /* -51.5 dB */ - 0x000b8b, /* -51.0 dB */ - 0x000c3a, /* -50.5 dB */ - 0x000cf3, /* -50.0 dB */ - 0x000db8, /* -49.5 dB */ - 0x000e88, /* -49.0 dB */ - 0x000f64, /* -48.5 dB */ - 0x00104e, /* -48.0 dB */ - 0x001145, /* -47.5 dB */ - 0x00124b, /* -47.0 dB */ - 0x001361, /* -46.5 dB */ - 0x001487, /* -46.0 dB */ - 0x0015be, /* -45.5 dB */ - 0x001708, /* -45.0 dB */ - 0x001865, /* -44.5 dB */ - 0x0019d8, /* -44.0 dB */ - 0x001b60, /* -43.5 dB */ - 0x001cff, /* -43.0 dB */ - 0x001eb7, /* -42.5 dB */ - 0x002089, /* -42.0 dB */ - 0x002276, /* -41.5 dB */ - 0x002481, /* -41.0 dB */ - 0x0026ab, /* -40.5 dB */ - 0x0028f5, /* -40.0 dB */ - 0x002b63, /* -39.5 dB */ - 0x002df5, /* -39.0 dB */ - 0x0030ae, /* -38.5 dB */ - 0x003390, /* -38.0 dB */ - 0x00369e, /* -37.5 dB */ - 0x0039db, /* -37.0 dB */ - 0x003d49, /* -36.5 dB */ - 0x0040ea, /* -36.0 dB */ - 0x0044c3, /* -35.5 dB */ - 0x0048d6, /* -35.0 dB */ - 0x004d27, /* -34.5 dB */ - 0x0051b9, /* -34.0 dB */ - 0x005691, /* -33.5 dB */ - 0x005bb2, /* -33.0 dB */ - 0x006121, /* -32.5 dB */ - 0x0066e3, /* -32.0 dB */ - 0x006cfb, /* -31.5 dB */ - 0x007370, /* -31.0 dB */ - 0x007a48, /* -30.5 dB */ - 0x008186, /* -30.0 dB */ - 0x008933, /* -29.5 dB */ - 0x009154, /* -29.0 dB */ - 0x0099f1, /* -28.5 dB */ - 0x00a310, /* -28.0 dB */ - 0x00acba, /* -27.5 dB */ - 0x00b6f6, /* -27.0 dB */ - 0x00c1cd, /* -26.5 dB */ - 0x00cd49, /* -26.0 dB */ - 0x00d973, /* -25.5 dB */ - 0x00e655, /* -25.0 dB */ - 0x00f3fb, /* -24.5 dB */ - 0x010270, /* -24.0 dB */ - 0x0111c0, /* -23.5 dB */ - 0x0121f9, /* -23.0 dB */ - 0x013328, /* -22.5 dB */ - 0x01455b, /* -22.0 dB */ - 0x0158a2, /* -21.5 dB */ - 0x016d0e, /* -21.0 dB */ - 0x0182af, /* -20.5 dB */ - 0x019999, /* -20.0 dB */ - 0x01b1de, /* -19.5 dB */ - 0x01cb94, /* -19.0 dB */ - 0x01e6cf, /* -18.5 dB */ - 0x0203a7, /* -18.0 dB */ - 0x022235, /* -17.5 dB */ - 0x024293, /* -17.0 dB */ - 0x0264db, /* -16.5 dB */ - 0x02892c, /* -16.0 dB */ - 0x02afa3, /* -15.5 dB */ - 0x02d862, /* -15.0 dB */ - 0x03038a, /* -14.5 dB */ - 0x033142, /* -14.0 dB */ - 0x0361af, /* -13.5 dB */ - 0x0394fa, /* -13.0 dB */ - 0x03cb50, /* -12.5 dB */ - 0x0404de, /* -12.0 dB */ - 0x0441d5, /* -11.5 dB */ - 0x048268, /* -11.0 dB */ - 0x04c6d0, /* -10.5 dB */ - 0x050f44, /* -10.0 dB */ - 0x055c04, /* -9.5 dB */ - 0x05ad50, /* -9.0 dB */ - 0x06036e, /* -8.5 dB */ - 0x065ea5, /* -8.0 dB */ - 0x06bf44, /* -7.5 dB */ - 0x07259d, /* -7.0 dB */ - 0x079207, /* -6.5 dB */ - 0x0804dc, /* -6.0 dB */ - 0x087e80, /* -5.5 dB */ - 0x08ff59, /* -5.0 dB */ - 0x0987d5, /* -4.5 dB */ - 0x0a1866, /* -4.0 dB */ - 0x0ab189, /* -3.5 dB */ - 0x0b53be, /* -3.0 dB */ - 0x0bff91, /* -2.5 dB */ - 0x0cb591, /* -2.0 dB */ - 0x0d765a, /* -1.5 dB */ - 0x0e4290, /* -1.0 dB */ - 0x0f1adf, /* -0.5 dB */ - 0x100000, /* 0.0 dB */ - 0x10f2b4, /* 0.5 dB */ - 0x11f3c9, /* 1.0 dB */ - 0x13041a, /* 1.5 dB */ - 0x14248e, /* 2.0 dB */ - 0x15561a, /* 2.5 dB */ - 0x1699c0, /* 3.0 dB */ - 0x17f094, /* 3.5 dB */ - 0x195bb8, /* 4.0 dB */ - 0x1adc61, /* 4.5 dB */ - 0x1c73d5, /* 5.0 dB */ - 0x1e236d, /* 5.5 dB */ - 0x1fec98, /* 6.0 dB */ - 0x21d0d9, /* 6.5 dB */ - 0x23d1cd, /* 7.0 dB */ - 0x25f125, /* 7.5 dB */ - 0x2830af, /* 8.0 dB */ - 0x2a9254, /* 8.5 dB */ - 0x2d1818, /* 9.0 dB */ - 0x2fc420, /* 9.5 dB */ - 0x3298b0, /* 10.0 dB */ - 0x35982f, /* 10.5 dB */ - 0x38c528, /* 11.0 dB */ - 0x3c224c, /* 11.5 dB */ - 0x3fb278, /* 12.0 dB */ - 0x4378b0, /* 12.5 dB */ - 0x477829, /* 13.0 dB */ - 0x4bb446, /* 13.5 dB */ - 0x5030a1, /* 14.0 dB */ - 0x54f106, /* 14.5 dB */ - 0x59f980, /* 15.0 dB */ - 0x5f4e52, /* 15.5 dB */ - 0x64f403, /* 16.0 dB */ - 0x6aef5e, /* 16.5 dB */ - 0x714575, /* 17.0 dB */ - 0x77fbaa, /* 17.5 dB */ - 0x7f17af, /* 18.0 dB */ -}; - diff --git a/ANDROID_3.4.5/sound/aoa/codecs/tas.c b/ANDROID_3.4.5/sound/aoa/codecs/tas.c deleted file mode 100644 index 8e63d1f3..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/tas.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * Apple Onboard Audio driver for tas codec - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - * - * Open questions: - * - How to distinguish between 3004 and versions? - * - * FIXMEs: - * - This codec driver doesn't honour the 'connected' - * property of the aoa_codec struct, hence if - * it is used in machines where not everything is - * connected it will display wrong mixer elements. - * - Driver assumes that the microphone is always - * monaureal and connected to the right channel of - * the input. This should also be a codec-dependent - * flag, maybe the codec should have 3 different - * bits for the three different possibilities how - * it can be hooked up... - * But as long as I don't see any hardware hooked - * up that way... - * - As Apple notes in their code, the tas3004 seems - * to delay the right channel by one sample. You can - * see this when for example recording stereo in - * audacity, or recording the tas output via cable - * on another machine (use a sinus generator or so). - * I tried programming the BiQuads but couldn't - * make the delay work, maybe someone can read the - * datasheet and fix it. The relevant Apple comment - * is in AppleTAS3004Audio.cpp lines 1637 ff. Note - * that their comment describing how they program - * the filters sucks... - * - * Other things: - * - this should actually register *two* aoa_codec - * structs since it has two inputs. Then it must - * use the prepare callback to forbid running the - * secondary output on a different clock. - * Also, whatever bus knows how to do this must - * provide two soundbus_dev devices and the fabric - * must be able to link them correctly. - * - * I don't even know if Apple ever uses the second - * port on the tas3004 though, I don't think their - * i2s controllers can even do it. OTOH, they all - * derive the clocks from common clocks, so it - * might just be possible. The framework allows the - * codec to refine the transfer_info items in the - * usable callback, so we can simply remove the - * rates the second instance is not using when it - * actually is in use. - * Maybe we'll need to make the sound busses have - * a 'clock group id' value so the codec can - * determine if the two outputs can be driven at - * the same time. But that is likely overkill, up - * to the fabric to not link them up incorrectly, - * and up to the hardware designer to not wire - * them up in some weird unusable way. - */ -#include <stddef.h> -#include <linux/i2c.h> -#include <asm/pmac_low_i2c.h> -#include <asm/prom.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/slab.h> - -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("tas codec driver for snd-aoa"); - -#include "tas.h" -#include "tas-gain-table.h" -#include "tas-basstreble.h" -#include "../aoa.h" -#include "../soundbus/soundbus.h" - -#define PFX "snd-aoa-codec-tas: " - - -struct tas { - struct aoa_codec codec; - struct i2c_client *i2c; - u32 mute_l:1, mute_r:1 , - controls_created:1 , - drc_enabled:1, - hw_enabled:1; - u8 cached_volume_l, cached_volume_r; - u8 mixer_l[3], mixer_r[3]; - u8 bass, treble; - u8 acr; - int drc_range; - /* protects hardware access against concurrency from - * userspace when hitting controls and during - * codec init/suspend/resume */ - struct mutex mtx; -}; - -static int tas_reset_init(struct tas *tas); - -static struct tas *codec_to_tas(struct aoa_codec *codec) -{ - return container_of(codec, struct tas, codec); -} - -static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data) -{ - if (len == 1) - return i2c_smbus_write_byte_data(tas->i2c, reg, *data); - else - return i2c_smbus_write_i2c_block_data(tas->i2c, reg, len, data); -} - -static void tas3004_set_drc(struct tas *tas) -{ - unsigned char val[6]; - - if (tas->drc_enabled) - val[0] = 0x50; /* 3:1 above threshold */ - else - val[0] = 0x51; /* disabled */ - val[1] = 0x02; /* 1:1 below threshold */ - if (tas->drc_range > 0xef) - val[2] = 0xef; - else if (tas->drc_range < 0) - val[2] = 0x00; - else - val[2] = tas->drc_range; - val[3] = 0xb0; - val[4] = 0x60; - val[5] = 0xa0; - - tas_write_reg(tas, TAS_REG_DRC, 6, val); -} - -static void tas_set_treble(struct tas *tas) -{ - u8 tmp; - - tmp = tas3004_treble(tas->treble); - tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp); -} - -static void tas_set_bass(struct tas *tas) -{ - u8 tmp; - - tmp = tas3004_bass(tas->bass); - tas_write_reg(tas, TAS_REG_BASS, 1, &tmp); -} - -static void tas_set_volume(struct tas *tas) -{ - u8 block[6]; - int tmp; - u8 left, right; - - left = tas->cached_volume_l; - right = tas->cached_volume_r; - - if (left > 177) left = 177; - if (right > 177) right = 177; - - if (tas->mute_l) left = 0; - if (tas->mute_r) right = 0; - - /* analysing the volume and mixer tables shows - * that they are similar enough when we shift - * the mixer table down by 4 bits. The error - * is miniscule, in just one item the error - * is 1, at a value of 0x07f17b (mixer table - * value is 0x07f17a) */ - tmp = tas_gaintable[left]; - block[0] = tmp>>20; - block[1] = tmp>>12; - block[2] = tmp>>4; - tmp = tas_gaintable[right]; - block[3] = tmp>>20; - block[4] = tmp>>12; - block[5] = tmp>>4; - tas_write_reg(tas, TAS_REG_VOL, 6, block); -} - -static void tas_set_mixer(struct tas *tas) -{ - u8 block[9]; - int tmp, i; - u8 val; - - for (i=0;i<3;i++) { - val = tas->mixer_l[i]; - if (val > 177) val = 177; - tmp = tas_gaintable[val]; - block[3*i+0] = tmp>>16; - block[3*i+1] = tmp>>8; - block[3*i+2] = tmp; - } - tas_write_reg(tas, TAS_REG_LMIX, 9, block); - - for (i=0;i<3;i++) { - val = tas->mixer_r[i]; - if (val > 177) val = 177; - tmp = tas_gaintable[val]; - block[3*i+0] = tmp>>16; - block[3*i+1] = tmp>>8; - block[3*i+2] = tmp; - } - tas_write_reg(tas, TAS_REG_RMIX, 9, block); -} - -/* alsa stuff */ - -static int tas_dev_register(struct snd_device *dev) -{ - return 0; -} - -static struct snd_device_ops ops = { - .dev_register = tas_dev_register, -}; - -static int tas_snd_vol_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 = 177; - return 0; -} - -static int tas_snd_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = tas->cached_volume_l; - ucontrol->value.integer.value[1] = tas->cached_volume_r; - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - if (ucontrol->value.integer.value[0] < 0 || - ucontrol->value.integer.value[0] > 177) - return -EINVAL; - if (ucontrol->value.integer.value[1] < 0 || - ucontrol->value.integer.value[1] > 177) - return -EINVAL; - - mutex_lock(&tas->mtx); - if (tas->cached_volume_l == ucontrol->value.integer.value[0] - && tas->cached_volume_r == ucontrol->value.integer.value[1]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->cached_volume_l = ucontrol->value.integer.value[0]; - tas->cached_volume_r = ucontrol->value.integer.value[1]; - if (tas->hw_enabled) - tas_set_volume(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new volume_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_vol_info, - .get = tas_snd_vol_get, - .put = tas_snd_vol_put, -}; - -#define tas_snd_mute_info snd_ctl_boolean_stereo_info - -static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = !tas->mute_l; - ucontrol->value.integer.value[1] = !tas->mute_r; - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - if (tas->mute_l == !ucontrol->value.integer.value[0] - && tas->mute_r == !ucontrol->value.integer.value[1]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->mute_l = !ucontrol->value.integer.value[0]; - tas->mute_r = !ucontrol->value.integer.value[1]; - if (tas->hw_enabled) - tas_set_volume(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new mute_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_mute_info, - .get = tas_snd_mute_get, - .put = tas_snd_mute_put, -}; - -static int tas_snd_mixer_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 = 177; - return 0; -} - -static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = tas->mixer_l[idx]; - ucontrol->value.integer.value[1] = tas->mixer_r[idx]; - mutex_unlock(&tas->mtx); - - return 0; -} - -static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->private_value; - - mutex_lock(&tas->mtx); - if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] - && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->mixer_l[idx] = ucontrol->value.integer.value[0]; - tas->mixer_r[idx] = ucontrol->value.integer.value[1]; - - if (tas->hw_enabled) - tas_set_mixer(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -#define MIXER_CONTROL(n,descr,idx) \ -static struct snd_kcontrol_new n##_control = { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = descr " Playback Volume", \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = tas_snd_mixer_info, \ - .get = tas_snd_mixer_get, \ - .put = tas_snd_mixer_put, \ - .private_value = idx, \ -} - -MIXER_CONTROL(pcm1, "PCM", 0); -MIXER_CONTROL(monitor, "Monitor", 2); - -static int tas_snd_drc_range_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = TAS3004_DRC_MAX; - return 0; -} - -static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = tas->drc_range; - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - if (ucontrol->value.integer.value[0] < 0 || - ucontrol->value.integer.value[0] > TAS3004_DRC_MAX) - return -EINVAL; - - mutex_lock(&tas->mtx); - if (tas->drc_range == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->drc_range = ucontrol->value.integer.value[0]; - if (tas->hw_enabled) - tas3004_set_drc(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new drc_range_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DRC Range", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_drc_range_info, - .get = tas_snd_drc_range_get, - .put = tas_snd_drc_range_put, -}; - -#define tas_snd_drc_switch_info snd_ctl_boolean_mono_info - -static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = tas->drc_enabled; - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - if (tas->drc_enabled == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->drc_enabled = !!ucontrol->value.integer.value[0]; - if (tas->hw_enabled) - tas3004_set_drc(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new drc_switch_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DRC Range Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_drc_switch_info, - .get = tas_snd_drc_switch_get, - .put = tas_snd_drc_switch_put, -}; - -static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { "Line-In", "Microphone" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - int oldacr; - - if (ucontrol->value.enumerated.item[0] > 1) - return -EINVAL; - mutex_lock(&tas->mtx); - oldacr = tas->acr; - - /* - * Despite what the data sheet says in one place, the - * TAS_ACR_B_MONAUREAL bit forces mono output even when - * input A (line in) is selected. - */ - tas->acr &= ~(TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL); - if (ucontrol->value.enumerated.item[0]) - tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL | - TAS_ACR_B_MON_SEL_RIGHT; - if (oldacr == tas->acr) { - mutex_unlock(&tas->mtx); - return 0; - } - if (tas->hw_enabled) - tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new capture_source_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* If we name this 'Input Source', it properly shows up in - * alsamixer as a selection, * but it's shown under the - * 'Playback' category. - * If I name it 'Capture Source', it shows up in strange - * ways (two bools of which one can be selected at a - * time) but at least it's shown in the 'Capture' - * category. - * I was told that this was due to backward compatibility, - * but I don't understand then why the mangling is *not* - * done when I name it "Input Source"..... - */ - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_capture_source_info, - .get = tas_snd_capture_source_get, - .put = tas_snd_capture_source_put, -}; - -static int tas_snd_treble_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = TAS3004_TREBLE_MIN; - uinfo->value.integer.max = TAS3004_TREBLE_MAX; - return 0; -} - -static int tas_snd_treble_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = tas->treble; - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN || - ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX) - return -EINVAL; - mutex_lock(&tas->mtx); - if (tas->treble == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->treble = ucontrol->value.integer.value[0]; - if (tas->hw_enabled) - tas_set_treble(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new treble_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Treble", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_treble_info, - .get = tas_snd_treble_get, - .put = tas_snd_treble_put, -}; - -static int tas_snd_bass_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = TAS3004_BASS_MIN; - uinfo->value.integer.max = TAS3004_BASS_MAX; - return 0; -} - -static int tas_snd_bass_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas->mtx); - ucontrol->value.integer.value[0] = tas->bass; - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tas *tas = snd_kcontrol_chip(kcontrol); - - if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN || - ucontrol->value.integer.value[0] > TAS3004_BASS_MAX) - return -EINVAL; - mutex_lock(&tas->mtx); - if (tas->bass == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); - return 0; - } - - tas->bass = ucontrol->value.integer.value[0]; - if (tas->hw_enabled) - tas_set_bass(tas); - mutex_unlock(&tas->mtx); - return 1; -} - -static struct snd_kcontrol_new bass_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Bass", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = tas_snd_bass_info, - .get = tas_snd_bass_get, - .put = tas_snd_bass_put, -}; - -static struct transfer_info tas_transfers[] = { - { - /* input */ - .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_BE, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .transfer_in = 1, - }, - { - /* output */ - .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_BE, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .transfer_in = 0, - }, - {} -}; - -static int tas_usable(struct codec_info_item *cii, - struct transfer_info *ti, - struct transfer_info *out) -{ - return 1; -} - -static int tas_reset_init(struct tas *tas) -{ - u8 tmp; - - tas->codec.gpio->methods->all_amps_off(tas->codec.gpio); - msleep(5); - tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); - msleep(5); - tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1); - msleep(20); - tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); - msleep(10); - tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); - - tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; - if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) - goto outerr; - - tas->acr |= TAS_ACR_ANALOG_PDOWN; - if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) - goto outerr; - - tmp = 0; - if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) - goto outerr; - - tas3004_set_drc(tas); - - /* Set treble & bass to 0dB */ - tas->treble = TAS3004_TREBLE_ZERO; - tas->bass = TAS3004_BASS_ZERO; - tas_set_treble(tas); - tas_set_bass(tas); - - tas->acr &= ~TAS_ACR_ANALOG_PDOWN; - if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) - goto outerr; - - return 0; - outerr: - return -ENODEV; -} - -static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) -{ - struct tas *tas = cii->codec_data; - - switch(clock) { - case CLOCK_SWITCH_PREPARE_SLAVE: - /* Clocks are going away, mute mute mute */ - tas->codec.gpio->methods->all_amps_off(tas->codec.gpio); - tas->hw_enabled = 0; - break; - case CLOCK_SWITCH_SLAVE: - /* Clocks are back, re-init the codec */ - mutex_lock(&tas->mtx); - tas_reset_init(tas); - tas_set_volume(tas); - tas_set_mixer(tas); - tas->hw_enabled = 1; - tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); - mutex_unlock(&tas->mtx); - break; - default: - /* doesn't happen as of now */ - return -EINVAL; - } - return 0; -} - -#ifdef CONFIG_PM -/* we are controlled via i2c and assume that is always up - * If that wasn't the case, we'd have to suspend once - * our i2c device is suspended, and then take note of that! */ -static int tas_suspend(struct tas *tas) -{ - mutex_lock(&tas->mtx); - tas->hw_enabled = 0; - tas->acr |= TAS_ACR_ANALOG_PDOWN; - tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); - mutex_unlock(&tas->mtx); - return 0; -} - -static int tas_resume(struct tas *tas) -{ - /* reset codec */ - mutex_lock(&tas->mtx); - tas_reset_init(tas); - tas_set_volume(tas); - tas_set_mixer(tas); - tas->hw_enabled = 1; - mutex_unlock(&tas->mtx); - return 0; -} - -static int _tas_suspend(struct codec_info_item *cii, pm_message_t state) -{ - return tas_suspend(cii->codec_data); -} - -static int _tas_resume(struct codec_info_item *cii) -{ - return tas_resume(cii->codec_data); -} -#else /* CONFIG_PM */ -#define _tas_suspend NULL -#define _tas_resume NULL -#endif /* CONFIG_PM */ - -static struct codec_info tas_codec_info = { - .transfers = tas_transfers, - /* in theory, we can drive it at 512 too... - * but so far the framework doesn't allow - * for that and I don't see much point in it. */ - .sysclock_factor = 256, - /* same here, could be 32 for just one 16 bit format */ - .bus_factor = 64, - .owner = THIS_MODULE, - .usable = tas_usable, - .switch_clock = tas_switch_clock, - .suspend = _tas_suspend, - .resume = _tas_resume, -}; - -static int tas_init_codec(struct aoa_codec *codec) -{ - struct tas *tas = codec_to_tas(codec); - int err; - - if (!tas->codec.gpio || !tas->codec.gpio->methods) { - printk(KERN_ERR PFX "gpios not assigned!!\n"); - return -EINVAL; - } - - mutex_lock(&tas->mtx); - if (tas_reset_init(tas)) { - printk(KERN_ERR PFX "tas failed to initialise\n"); - mutex_unlock(&tas->mtx); - return -ENXIO; - } - tas->hw_enabled = 1; - mutex_unlock(&tas->mtx); - - if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, - aoa_get_card(), - &tas_codec_info, tas)) { - printk(KERN_ERR PFX "error attaching tas to soundbus\n"); - return -ENODEV; - } - - if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) { - printk(KERN_ERR PFX "failed to create tas snd device!\n"); - return -ENODEV; - } - err = aoa_snd_ctl_add(snd_ctl_new1(&volume_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&mute_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&pcm1_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&capture_source_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&drc_range_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&drc_switch_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&treble_control, tas)); - if (err) - goto error; - - err = aoa_snd_ctl_add(snd_ctl_new1(&bass_control, tas)); - if (err) - goto error; - - return 0; - error: - tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); - snd_device_free(aoa_get_card(), tas); - return err; -} - -static void tas_exit_codec(struct aoa_codec *codec) -{ - struct tas *tas = codec_to_tas(codec); - - if (!tas->codec.soundbus_dev) - return; - tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); -} - - -static int tas_create(struct i2c_adapter *adapter, - struct device_node *node, - int addr) -{ - struct i2c_board_info info; - struct i2c_client *client; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "aoa_codec_tas", I2C_NAME_SIZE); - info.addr = addr; - info.platform_data = node; - - client = i2c_new_device(adapter, &info); - if (!client) - return -ENODEV; - /* - * We know the driver is already loaded, so the device should be - * already bound. If not it means binding failed, and then there - * is no point in keeping the device instantiated. - */ - if (!client->driver) { - i2c_unregister_device(client); - return -ENODEV; - } - - /* - * Let i2c-core delete that device on driver removal. - * This is safe because i2c-core holds the core_lock mutex for us. - */ - list_add_tail(&client->detected, &client->driver->clients); - return 0; -} - -static int tas_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device_node *node = client->dev.platform_data; - struct tas *tas; - - tas = kzalloc(sizeof(struct tas), GFP_KERNEL); - - if (!tas) - return -ENOMEM; - - mutex_init(&tas->mtx); - tas->i2c = client; - i2c_set_clientdata(client, tas); - - /* seems that half is a saner default */ - tas->drc_range = TAS3004_DRC_MAX / 2; - - strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN); - tas->codec.owner = THIS_MODULE; - tas->codec.init = tas_init_codec; - tas->codec.exit = tas_exit_codec; - tas->codec.node = of_node_get(node); - - if (aoa_codec_register(&tas->codec)) { - goto fail; - } - printk(KERN_DEBUG - "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n", - (unsigned int)client->addr, node->full_name); - return 0; - fail: - mutex_destroy(&tas->mtx); - kfree(tas); - return -EINVAL; -} - -static int tas_i2c_attach(struct i2c_adapter *adapter) -{ - struct device_node *busnode, *dev = NULL; - struct pmac_i2c_bus *bus; - - bus = pmac_i2c_adapter_to_bus(adapter); - if (bus == NULL) - return -ENODEV; - busnode = pmac_i2c_get_bus_node(bus); - - while ((dev = of_get_next_child(busnode, dev)) != NULL) { - if (of_device_is_compatible(dev, "tas3004")) { - const u32 *addr; - printk(KERN_DEBUG PFX "found tas3004\n"); - addr = of_get_property(dev, "reg", NULL); - if (!addr) - continue; - return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f); - } - /* older machines have no 'codec' node with a 'compatible' - * property that says 'tas3004', they just have a 'deq' - * node without any such property... */ - if (strcmp(dev->name, "deq") == 0) { - const u32 *_addr; - u32 addr; - printk(KERN_DEBUG PFX "found 'deq' node\n"); - _addr = of_get_property(dev, "i2c-address", NULL); - if (!_addr) - continue; - addr = ((*_addr) >> 1) & 0x7f; - /* now, if the address doesn't match any of the two - * that a tas3004 can have, we cannot handle this. - * I doubt it ever happens but hey. */ - if (addr != 0x34 && addr != 0x35) - continue; - return tas_create(adapter, dev, addr); - } - } - return -ENODEV; -} - -static int tas_i2c_remove(struct i2c_client *client) -{ - struct tas *tas = i2c_get_clientdata(client); - u8 tmp = TAS_ACR_ANALOG_PDOWN; - - aoa_codec_unregister(&tas->codec); - of_node_put(tas->codec.node); - - /* power down codec chip */ - tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); - - mutex_destroy(&tas->mtx); - kfree(tas); - return 0; -} - -static const struct i2c_device_id tas_i2c_id[] = { - { "aoa_codec_tas", 0 }, - { } -}; - -static struct i2c_driver tas_driver = { - .driver = { - .name = "aoa_codec_tas", - .owner = THIS_MODULE, - }, - .attach_adapter = tas_i2c_attach, - .probe = tas_i2c_probe, - .remove = tas_i2c_remove, - .id_table = tas_i2c_id, -}; - -module_i2c_driver(tas_driver); diff --git a/ANDROID_3.4.5/sound/aoa/codecs/tas.h b/ANDROID_3.4.5/sound/aoa/codecs/tas.h deleted file mode 100644 index ae177e34..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/tas.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Apple Onboard Audio driver for tas codec (header) - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ -#ifndef __SND_AOA_CODECTASH -#define __SND_AOA_CODECTASH - -#define TAS_REG_MCS 0x01 /* main control */ -# define TAS_MCS_FASTLOAD (1<<7) -# define TAS_MCS_SCLK64 (1<<6) -# define TAS_MCS_SPORT_MODE_MASK (3<<4) -# define TAS_MCS_SPORT_MODE_I2S (2<<4) -# define TAS_MCS_SPORT_MODE_RJ (1<<4) -# define TAS_MCS_SPORT_MODE_LJ (0<<4) -# define TAS_MCS_SPORT_WL_MASK (3<<0) -# define TAS_MCS_SPORT_WL_16BIT (0<<0) -# define TAS_MCS_SPORT_WL_18BIT (1<<0) -# define TAS_MCS_SPORT_WL_20BIT (2<<0) -# define TAS_MCS_SPORT_WL_24BIT (3<<0) - -#define TAS_REG_DRC 0x02 -#define TAS_REG_VOL 0x04 -#define TAS_REG_TREBLE 0x05 -#define TAS_REG_BASS 0x06 -#define TAS_REG_LMIX 0x07 -#define TAS_REG_RMIX 0x08 - -#define TAS_REG_ACR 0x40 /* analog control */ -# define TAS_ACR_B_MONAUREAL (1<<7) -# define TAS_ACR_B_MON_SEL_RIGHT (1<<6) -# define TAS_ACR_DEEMPH_MASK (3<<2) -# define TAS_ACR_DEEMPH_OFF (0<<2) -# define TAS_ACR_DEEMPH_48KHz (1<<2) -# define TAS_ACR_DEEMPH_44KHz (2<<2) -# define TAS_ACR_INPUT_B (1<<1) -# define TAS_ACR_ANALOG_PDOWN (1<<0) - -#define TAS_REG_MCS2 0x43 /* main control 2 */ -# define TAS_MCS2_ALLPASS (1<<1) - -#define TAS_REG_LEFT_BIQUAD6 0x10 -#define TAS_REG_RIGHT_BIQUAD6 0x19 - -#define TAS_REG_LEFT_LOUDNESS 0x21 -#define TAS_REG_RIGHT_LOUDNESS 0x22 -#define TAS_REG_LEFT_LOUDNESS_GAIN 0x23 -#define TAS_REG_RIGHT_LOUDNESS_GAIN 0x24 - -#define TAS3001_DRC_MAX 0x5f -#define TAS3004_DRC_MAX 0xef - -#endif /* __SND_AOA_CODECTASH */ diff --git a/ANDROID_3.4.5/sound/aoa/codecs/toonie.c b/ANDROID_3.4.5/sound/aoa/codecs/toonie.c deleted file mode 100644 index 69d2cb60..00000000 --- a/ANDROID_3.4.5/sound/aoa/codecs/toonie.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Apple Onboard Audio driver for Toonie codec - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - * - * - * This is a driver for the toonie codec chip. This chip is present - * on the Mac Mini and is nothing but a DAC. - */ -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/slab.h> -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("toonie codec driver for snd-aoa"); - -#include "../aoa.h" -#include "../soundbus/soundbus.h" - - -#define PFX "snd-aoa-codec-toonie: " - -struct toonie { - struct aoa_codec codec; -}; -#define codec_to_toonie(c) container_of(c, struct toonie, codec) - -static int toonie_dev_register(struct snd_device *dev) -{ - return 0; -} - -static struct snd_device_ops ops = { - .dev_register = toonie_dev_register, -}; - -static struct transfer_info toonie_transfers[] = { - /* This thing *only* has analog output, - * the rates are taken from Info.plist - * from Darwin. */ - { - .formats = SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, - }, - {} -}; - -static int toonie_usable(struct codec_info_item *cii, - struct transfer_info *ti, - struct transfer_info *out) -{ - return 1; -} - -#ifdef CONFIG_PM -static int toonie_suspend(struct codec_info_item *cii, pm_message_t state) -{ - /* can we turn it off somehow? */ - return 0; -} - -static int toonie_resume(struct codec_info_item *cii) -{ - return 0; -} -#endif /* CONFIG_PM */ - -static struct codec_info toonie_codec_info = { - .transfers = toonie_transfers, - .sysclock_factor = 256, - .bus_factor = 64, - .owner = THIS_MODULE, - .usable = toonie_usable, -#ifdef CONFIG_PM - .suspend = toonie_suspend, - .resume = toonie_resume, -#endif -}; - -static int toonie_init_codec(struct aoa_codec *codec) -{ - struct toonie *toonie = codec_to_toonie(codec); - - /* nothing connected? what a joke! */ - if (toonie->codec.connected != 1) - return -ENOTCONN; - - if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) { - printk(KERN_ERR PFX "failed to create toonie snd device!\n"); - return -ENODEV; - } - - if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev, - aoa_get_card(), - &toonie_codec_info, toonie)) { - printk(KERN_ERR PFX "error creating toonie pcm\n"); - snd_device_free(aoa_get_card(), toonie); - return -ENODEV; - } - - return 0; -} - -static void toonie_exit_codec(struct aoa_codec *codec) -{ - struct toonie *toonie = codec_to_toonie(codec); - - if (!toonie->codec.soundbus_dev) { - printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n"); - return; - } - toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie); -} - -static struct toonie *toonie; - -static int __init toonie_init(void) -{ - toonie = kzalloc(sizeof(struct toonie), GFP_KERNEL); - - if (!toonie) - return -ENOMEM; - - strlcpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name)); - toonie->codec.owner = THIS_MODULE; - toonie->codec.init = toonie_init_codec; - toonie->codec.exit = toonie_exit_codec; - - if (aoa_codec_register(&toonie->codec)) { - kfree(toonie); - return -EINVAL; - } - - return 0; -} - -static void __exit toonie_exit(void) -{ - aoa_codec_unregister(&toonie->codec); - kfree(toonie); -} - -module_init(toonie_init); -module_exit(toonie_exit); diff --git a/ANDROID_3.4.5/sound/aoa/core/Makefile b/ANDROID_3.4.5/sound/aoa/core/Makefile deleted file mode 100644 index a1596e88..00000000 --- a/ANDROID_3.4.5/sound/aoa/core/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_SND_AOA) += snd-aoa.o -snd-aoa-objs := core.o \ - alsa.o \ - gpio-pmf.o \ - gpio-feature.o diff --git a/ANDROID_3.4.5/sound/aoa/core/alsa.c b/ANDROID_3.4.5/sound/aoa/core/alsa.c deleted file mode 100644 index 0fa3855b..00000000 --- a/ANDROID_3.4.5/sound/aoa/core/alsa.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Apple Onboard Audio Alsa helpers - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ -#include <linux/module.h> -#include "alsa.h" - -static int index = -1; -module_param(index, int, 0444); -MODULE_PARM_DESC(index, "index for AOA sound card."); - -static struct aoa_card *aoa_card; - -int aoa_alsa_init(char *name, struct module *mod, struct device *dev) -{ - struct snd_card *alsa_card; - int err; - - if (aoa_card) - /* cannot be EEXIST due to usage in aoa_fabric_register */ - return -EBUSY; - - err = snd_card_create(index, name, mod, sizeof(struct aoa_card), - &alsa_card); - if (err < 0) - return err; - aoa_card = alsa_card->private_data; - aoa_card->alsa_card = alsa_card; - alsa_card->dev = dev; - strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); - strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); - strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname)); - strlcpy(alsa_card->mixername, name, sizeof(alsa_card->mixername)); - err = snd_card_register(aoa_card->alsa_card); - if (err < 0) { - printk(KERN_ERR "snd-aoa: couldn't register alsa card\n"); - snd_card_free(aoa_card->alsa_card); - aoa_card = NULL; - return err; - } - return 0; -} - -struct snd_card *aoa_get_card(void) -{ - if (aoa_card) - return aoa_card->alsa_card; - return NULL; -} -EXPORT_SYMBOL_GPL(aoa_get_card); - -void aoa_alsa_cleanup(void) -{ - if (aoa_card) { - snd_card_free(aoa_card->alsa_card); - aoa_card = NULL; - } -} - -int aoa_snd_device_new(snd_device_type_t type, - void * device_data, struct snd_device_ops * ops) -{ - struct snd_card *card = aoa_get_card(); - int err; - - if (!card) return -ENOMEM; - - err = snd_device_new(card, type, device_data, ops); - if (err) { - printk(KERN_ERR "snd-aoa: failed to create snd device (%d)\n", err); - return err; - } - err = snd_device_register(card, device_data); - if (err) { - printk(KERN_ERR "snd-aoa: failed to register " - "snd device (%d)\n", err); - printk(KERN_ERR "snd-aoa: have you forgotten the " - "dev_register callback?\n"); - snd_device_free(card, device_data); - } - return err; -} -EXPORT_SYMBOL_GPL(aoa_snd_device_new); - -int aoa_snd_ctl_add(struct snd_kcontrol* control) -{ - int err; - - if (!aoa_card) return -ENODEV; - - err = snd_ctl_add(aoa_card->alsa_card, control); - if (err) - printk(KERN_ERR "snd-aoa: failed to add alsa control (%d)\n", - err); - return err; -} -EXPORT_SYMBOL_GPL(aoa_snd_ctl_add); diff --git a/ANDROID_3.4.5/sound/aoa/core/alsa.h b/ANDROID_3.4.5/sound/aoa/core/alsa.h deleted file mode 100644 index 9669e448..00000000 --- a/ANDROID_3.4.5/sound/aoa/core/alsa.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Apple Onboard Audio Alsa private helpers - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#ifndef __SND_AOA_ALSA_H -#define __SND_AOA_ALSA_H -#include "../aoa.h" - -extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev); -extern void aoa_alsa_cleanup(void); - -#endif /* __SND_AOA_ALSA_H */ diff --git a/ANDROID_3.4.5/sound/aoa/core/core.c b/ANDROID_3.4.5/sound/aoa/core/core.c deleted file mode 100644 index 10bec6c6..00000000 --- a/ANDROID_3.4.5/sound/aoa/core/core.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Apple Onboard Audio driver core - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/list.h> -#include "../aoa.h" -#include "alsa.h" - -MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver"); -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_LICENSE("GPL"); - -/* We allow only one fabric. This simplifies things, - * and more don't really make that much sense */ -static struct aoa_fabric *fabric; -static LIST_HEAD(codec_list); - -static int attach_codec_to_fabric(struct aoa_codec *c) -{ - int err; - - if (!try_module_get(c->owner)) - return -EBUSY; - /* found_codec has to be assigned */ - err = -ENOENT; - if (fabric->found_codec) - err = fabric->found_codec(c); - if (err) { - module_put(c->owner); - printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n", - c->name); - return err; - } - c->fabric = fabric; - - err = 0; - if (c->init) - err = c->init(c); - if (err) { - printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name); - c->fabric = NULL; - if (fabric->remove_codec) - fabric->remove_codec(c); - module_put(c->owner); - return err; - } - if (fabric->attached_codec) - fabric->attached_codec(c); - return 0; -} - -int aoa_codec_register(struct aoa_codec *codec) -{ - int err = 0; - - /* if there's a fabric already, we can tell if we - * will want to have this codec, so propagate error - * through. Otherwise, this will happen later... */ - if (fabric) - err = attach_codec_to_fabric(codec); - if (!err) - list_add(&codec->list, &codec_list); - return err; -} -EXPORT_SYMBOL_GPL(aoa_codec_register); - -void aoa_codec_unregister(struct aoa_codec *codec) -{ - list_del(&codec->list); - if (codec->fabric && codec->exit) - codec->exit(codec); - if (fabric && fabric->remove_codec) - fabric->remove_codec(codec); - codec->fabric = NULL; - module_put(codec->owner); -} -EXPORT_SYMBOL_GPL(aoa_codec_unregister); - -int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev) -{ - struct aoa_codec *c; - int err; - - /* allow querying for presence of fabric - * (i.e. do this test first!) */ - if (new_fabric == fabric) { - err = -EALREADY; - goto attach; - } - if (fabric) - return -EEXIST; - if (!new_fabric) - return -EINVAL; - - err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev); - if (err) - return err; - - fabric = new_fabric; - - attach: - list_for_each_entry(c, &codec_list, list) { - if (c->fabric != fabric) - attach_codec_to_fabric(c); - } - return err; -} -EXPORT_SYMBOL_GPL(aoa_fabric_register); - -void aoa_fabric_unregister(struct aoa_fabric *old_fabric) -{ - struct aoa_codec *c; - - if (fabric != old_fabric) - return; - - list_for_each_entry(c, &codec_list, list) { - if (c->fabric) - aoa_fabric_unlink_codec(c); - } - - aoa_alsa_cleanup(); - - fabric = NULL; -} -EXPORT_SYMBOL_GPL(aoa_fabric_unregister); - -void aoa_fabric_unlink_codec(struct aoa_codec *codec) -{ - if (!codec->fabric) { - printk(KERN_ERR "snd-aoa: fabric unassigned " - "in aoa_fabric_unlink_codec\n"); - dump_stack(); - return; - } - if (codec->exit) - codec->exit(codec); - if (codec->fabric->remove_codec) - codec->fabric->remove_codec(codec); - codec->fabric = NULL; - module_put(codec->owner); -} -EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec); - -static int __init aoa_init(void) -{ - return 0; -} - -static void __exit aoa_exit(void) -{ - aoa_alsa_cleanup(); -} - -module_init(aoa_init); -module_exit(aoa_exit); diff --git a/ANDROID_3.4.5/sound/aoa/core/gpio-feature.c b/ANDROID_3.4.5/sound/aoa/core/gpio-feature.c deleted file mode 100644 index faa31749..00000000 --- a/ANDROID_3.4.5/sound/aoa/core/gpio-feature.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Apple Onboard Audio feature call GPIO control - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - * - * This file contains the GPIO control routines for - * direct (through feature calls) access to the GPIO - * registers. - */ - -#include <asm/pmac_feature.h> -#include <linux/interrupt.h> -#include "../aoa.h" - -/* TODO: these are lots of global variables - * that aren't used on most machines... - * Move them into a dynamically allocated - * structure and use that. - */ - -/* these are the GPIO numbers (register addresses as offsets into - * the GPIO space) */ -static int headphone_mute_gpio; -static int master_mute_gpio; -static int amp_mute_gpio; -static int lineout_mute_gpio; -static int hw_reset_gpio; -static int lineout_detect_gpio; -static int headphone_detect_gpio; -static int linein_detect_gpio; - -/* see the SWITCH_GPIO macro */ -static int headphone_mute_gpio_activestate; -static int master_mute_gpio_activestate; -static int amp_mute_gpio_activestate; -static int lineout_mute_gpio_activestate; -static int hw_reset_gpio_activestate; -static int lineout_detect_gpio_activestate; -static int headphone_detect_gpio_activestate; -static int linein_detect_gpio_activestate; - -/* node pointers that we save when getting the GPIO number - * to get the interrupt later */ -static struct device_node *lineout_detect_node; -static struct device_node *linein_detect_node; -static struct device_node *headphone_detect_node; - -static int lineout_detect_irq; -static int linein_detect_irq; -static int headphone_detect_irq; - -static struct device_node *get_gpio(char *name, - char *altname, - int *gpioptr, - int *gpioactiveptr) -{ - struct device_node *np, *gpio; - const u32 *reg; - const char *audio_gpio; - - *gpioptr = -1; - - /* check if we can get it the easy way ... */ - np = of_find_node_by_name(NULL, name); - if (!np) { - /* some machines have only gpioX/extint-gpioX nodes, - * and an audio-gpio property saying what it is ... - * So what we have to do is enumerate all children - * of the gpio node and check them all. */ - gpio = of_find_node_by_name(NULL, "gpio"); - if (!gpio) - return NULL; - while ((np = of_get_next_child(gpio, np))) { - audio_gpio = of_get_property(np, "audio-gpio", NULL); - if (!audio_gpio) - continue; - if (strcmp(audio_gpio, name) == 0) - break; - if (altname && (strcmp(audio_gpio, altname) == 0)) - break; - } - /* still not found, assume not there */ - if (!np) - return NULL; - } - - reg = of_get_property(np, "reg", NULL); - if (!reg) - return NULL; - - *gpioptr = *reg; - - /* this is a hack, usually the GPIOs 'reg' property - * should have the offset based from the GPIO space - * which is at 0x50, but apparently not always... */ - if (*gpioptr < 0x50) - *gpioptr += 0x50; - - reg = of_get_property(np, "audio-gpio-active-state", NULL); - if (!reg) - /* Apple seems to default to 1, but - * that doesn't seem right at least on most - * machines. So until proven that the opposite - * is necessary, we default to 0 - * (which, incidentally, snd-powermac also does...) */ - *gpioactiveptr = 0; - else - *gpioactiveptr = *reg; - - return np; -} - -static void get_irq(struct device_node * np, int *irqptr) -{ - if (np) - *irqptr = irq_of_parse_and_map(np, 0); - else - *irqptr = NO_IRQ; -} - -/* 0x4 is outenable, 0x1 is out, thus 4 or 5 */ -#define SWITCH_GPIO(name, v, on) \ - (((v)&~1) | ((on)? \ - (name##_gpio_activestate==0?4:5): \ - (name##_gpio_activestate==0?5:4))) - -#define FTR_GPIO(name, bit) \ -static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\ -{ \ - int v; \ - \ - if (unlikely(!rt)) return; \ - \ - if (name##_mute_gpio < 0) \ - return; \ - \ - v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, \ - name##_mute_gpio, \ - 0); \ - \ - /* muted = !on... */ \ - v = SWITCH_GPIO(name##_mute, v, !on); \ - \ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, \ - name##_mute_gpio, v); \ - \ - rt->implementation_private &= ~(1<<bit); \ - rt->implementation_private |= (!!on << bit); \ -} \ -static int ftr_gpio_get_##name(struct gpio_runtime *rt) \ -{ \ - if (unlikely(!rt)) return 0; \ - return (rt->implementation_private>>bit)&1; \ -} - -FTR_GPIO(headphone, 0); -FTR_GPIO(amp, 1); -FTR_GPIO(lineout, 2); -FTR_GPIO(master, 3); - -static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on) -{ - int v; - - if (unlikely(!rt)) return; - if (hw_reset_gpio < 0) - return; - - v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, - hw_reset_gpio, 0); - v = SWITCH_GPIO(hw_reset, v, on); - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, - hw_reset_gpio, v); -} - -static struct gpio_methods methods; - -static void ftr_gpio_all_amps_off(struct gpio_runtime *rt) -{ - int saved; - - if (unlikely(!rt)) return; - saved = rt->implementation_private; - ftr_gpio_set_headphone(rt, 0); - ftr_gpio_set_amp(rt, 0); - ftr_gpio_set_lineout(rt, 0); - if (methods.set_master) - ftr_gpio_set_master(rt, 0); - rt->implementation_private = saved; -} - -static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt) -{ - int s; - - if (unlikely(!rt)) return; - s = rt->implementation_private; - ftr_gpio_set_headphone(rt, (s>>0)&1); - ftr_gpio_set_amp(rt, (s>>1)&1); - ftr_gpio_set_lineout(rt, (s>>2)&1); - if (methods.set_master) - ftr_gpio_set_master(rt, (s>>3)&1); -} - -static void ftr_handle_notify(struct work_struct *work) -{ - struct gpio_notification *notif = - container_of(work, struct gpio_notification, work.work); - - mutex_lock(¬if->mutex); - if (notif->notify) - notif->notify(notif->data); - mutex_unlock(¬if->mutex); -} - -static void gpio_enable_dual_edge(int gpio) -{ - int v; - - if (gpio == -1) - return; - v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0); - v |= 0x80; /* enable dual edge */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio, v); -} - -static void ftr_gpio_init(struct gpio_runtime *rt) -{ - get_gpio("headphone-mute", NULL, - &headphone_mute_gpio, - &headphone_mute_gpio_activestate); - get_gpio("amp-mute", NULL, - &_mute_gpio, - &_mute_gpio_activestate); - get_gpio("lineout-mute", NULL, - &lineout_mute_gpio, - &lineout_mute_gpio_activestate); - get_gpio("hw-reset", "audio-hw-reset", - &hw_reset_gpio, - &hw_reset_gpio_activestate); - if (get_gpio("master-mute", NULL, - &master_mute_gpio, - &master_mute_gpio_activestate)) { - methods.set_master = ftr_gpio_set_master; - methods.get_master = ftr_gpio_get_master; - } - - headphone_detect_node = get_gpio("headphone-detect", NULL, - &headphone_detect_gpio, - &headphone_detect_gpio_activestate); - /* go Apple, and thanks for giving these different names - * across the board... */ - lineout_detect_node = get_gpio("lineout-detect", "line-output-detect", - &lineout_detect_gpio, - &lineout_detect_gpio_activestate); - linein_detect_node = get_gpio("linein-detect", "line-input-detect", - &linein_detect_gpio, - &linein_detect_gpio_activestate); - - gpio_enable_dual_edge(headphone_detect_gpio); - gpio_enable_dual_edge(lineout_detect_gpio); - gpio_enable_dual_edge(linein_detect_gpio); - - get_irq(headphone_detect_node, &headphone_detect_irq); - get_irq(lineout_detect_node, &lineout_detect_irq); - get_irq(linein_detect_node, &linein_detect_irq); - - ftr_gpio_all_amps_off(rt); - rt->implementation_private = 0; - INIT_DELAYED_WORK(&rt->headphone_notify.work, ftr_handle_notify); - INIT_DELAYED_WORK(&rt->line_in_notify.work, ftr_handle_notify); - INIT_DELAYED_WORK(&rt->line_out_notify.work, ftr_handle_notify); - mutex_init(&rt->headphone_notify.mutex); - mutex_init(&rt->line_in_notify.mutex); - mutex_init(&rt->line_out_notify.mutex); -} - -static void ftr_gpio_exit(struct gpio_runtime *rt) -{ - ftr_gpio_all_amps_off(rt); - rt->implementation_private = 0; - if (rt->headphone_notify.notify) - free_irq(headphone_detect_irq, &rt->headphone_notify); - if (rt->line_in_notify.gpio_private) - free_irq(linein_detect_irq, &rt->line_in_notify); - if (rt->line_out_notify.gpio_private) - free_irq(lineout_detect_irq, &rt->line_out_notify); - cancel_delayed_work_sync(&rt->headphone_notify.work); - cancel_delayed_work_sync(&rt->line_in_notify.work); - cancel_delayed_work_sync(&rt->line_out_notify.work); - mutex_destroy(&rt->headphone_notify.mutex); - mutex_destroy(&rt->line_in_notify.mutex); - mutex_destroy(&rt->line_out_notify.mutex); -} - -static irqreturn_t ftr_handle_notify_irq(int xx, void *data) -{ - struct gpio_notification *notif = data; - - schedule_delayed_work(¬if->work, 0); - - return IRQ_HANDLED; -} - -static int ftr_set_notify(struct gpio_runtime *rt, - enum notify_type type, - notify_func_t notify, - void *data) -{ - struct gpio_notification *notif; - notify_func_t old; - int irq; - char *name; - int err = -EBUSY; - - switch (type) { - case AOA_NOTIFY_HEADPHONE: - notif = &rt->headphone_notify; - name = "headphone-detect"; - irq = headphone_detect_irq; - break; - case AOA_NOTIFY_LINE_IN: - notif = &rt->line_in_notify; - name = "linein-detect"; - irq = linein_detect_irq; - break; - case AOA_NOTIFY_LINE_OUT: - notif = &rt->line_out_notify; - name = "lineout-detect"; - irq = lineout_detect_irq; - break; - default: - return -EINVAL; - } - - if (irq == NO_IRQ) - return -ENODEV; - - mutex_lock(¬if->mutex); - - old = notif->notify; - - if (!old && !notify) { - err = 0; - goto out_unlock; - } - - if (old && notify) { - if (old == notify && notif->data == data) - err = 0; - goto out_unlock; - } - - if (old && !notify) - free_irq(irq, notif); - - if (!old && notify) { - err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif); - if (err) - goto out_unlock; - } - - notif->notify = notify; - notif->data = data; - - err = 0; - out_unlock: - mutex_unlock(¬if->mutex); - return err; -} - -static int ftr_get_detect(struct gpio_runtime *rt, - enum notify_type type) -{ - int gpio, ret, active; - - switch (type) { - case AOA_NOTIFY_HEADPHONE: - gpio = headphone_detect_gpio; - active = headphone_detect_gpio_activestate; - break; - case AOA_NOTIFY_LINE_IN: - gpio = linein_detect_gpio; - active = linein_detect_gpio_activestate; - break; - case AOA_NOTIFY_LINE_OUT: - gpio = lineout_detect_gpio; - active = lineout_detect_gpio_activestate; - break; - default: - return -EINVAL; - } - - if (gpio == -1) - return -ENODEV; - - ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0); - if (ret < 0) - return ret; - return ((ret >> 1) & 1) == active; -} - -static struct gpio_methods methods = { - .init = ftr_gpio_init, - .exit = ftr_gpio_exit, - .all_amps_off = ftr_gpio_all_amps_off, - .all_amps_restore = ftr_gpio_all_amps_restore, - .set_headphone = ftr_gpio_set_headphone, - .set_speakers = ftr_gpio_set_amp, - .set_lineout = ftr_gpio_set_lineout, - .set_hw_reset = ftr_gpio_set_hw_reset, - .get_headphone = ftr_gpio_get_headphone, - .get_speakers = ftr_gpio_get_amp, - .get_lineout = ftr_gpio_get_lineout, - .set_notify = ftr_set_notify, - .get_detect = ftr_get_detect, -}; - -struct gpio_methods *ftr_gpio_methods = &methods; -EXPORT_SYMBOL_GPL(ftr_gpio_methods); diff --git a/ANDROID_3.4.5/sound/aoa/core/gpio-pmf.c b/ANDROID_3.4.5/sound/aoa/core/gpio-pmf.c deleted file mode 100644 index c8d8a1a6..00000000 --- a/ANDROID_3.4.5/sound/aoa/core/gpio-pmf.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Apple Onboard Audio pmf GPIOs - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#include <linux/slab.h> -#include <asm/pmac_feature.h> -#include <asm/pmac_pfunc.h> -#include "../aoa.h" - -#define PMF_GPIO(name, bit) \ -static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\ -{ \ - struct pmf_args args = { .count = 1, .u[0].v = !on }; \ - int rc; \ - \ - if (unlikely(!rt)) return; \ - rc = pmf_call_function(rt->node, #name "-mute", &args); \ - if (rc && rc != -ENODEV) \ - printk(KERN_WARNING "pmf_gpio_set_" #name \ - " failed, rc: %d\n", rc); \ - rt->implementation_private &= ~(1<<bit); \ - rt->implementation_private |= (!!on << bit); \ -} \ -static int pmf_gpio_get_##name(struct gpio_runtime *rt) \ -{ \ - if (unlikely(!rt)) return 0; \ - return (rt->implementation_private>>bit)&1; \ -} - -PMF_GPIO(headphone, 0); -PMF_GPIO(amp, 1); -PMF_GPIO(lineout, 2); - -static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on) -{ - struct pmf_args args = { .count = 1, .u[0].v = !!on }; - int rc; - - if (unlikely(!rt)) return; - rc = pmf_call_function(rt->node, "hw-reset", &args); - if (rc) - printk(KERN_WARNING "pmf_gpio_set_hw_reset" - " failed, rc: %d\n", rc); -} - -static void pmf_gpio_all_amps_off(struct gpio_runtime *rt) -{ - int saved; - - if (unlikely(!rt)) return; - saved = rt->implementation_private; - pmf_gpio_set_headphone(rt, 0); - pmf_gpio_set_amp(rt, 0); - pmf_gpio_set_lineout(rt, 0); - rt->implementation_private = saved; -} - -static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt) -{ - int s; - - if (unlikely(!rt)) return; - s = rt->implementation_private; - pmf_gpio_set_headphone(rt, (s>>0)&1); - pmf_gpio_set_amp(rt, (s>>1)&1); - pmf_gpio_set_lineout(rt, (s>>2)&1); -} - -static void pmf_handle_notify(struct work_struct *work) -{ - struct gpio_notification *notif = - container_of(work, struct gpio_notification, work.work); - - mutex_lock(¬if->mutex); - if (notif->notify) - notif->notify(notif->data); - mutex_unlock(¬if->mutex); -} - -static void pmf_gpio_init(struct gpio_runtime *rt) -{ - pmf_gpio_all_amps_off(rt); - rt->implementation_private = 0; - INIT_DELAYED_WORK(&rt->headphone_notify.work, pmf_handle_notify); - INIT_DELAYED_WORK(&rt->line_in_notify.work, pmf_handle_notify); - INIT_DELAYED_WORK(&rt->line_out_notify.work, pmf_handle_notify); - mutex_init(&rt->headphone_notify.mutex); - mutex_init(&rt->line_in_notify.mutex); - mutex_init(&rt->line_out_notify.mutex); -} - -static void pmf_gpio_exit(struct gpio_runtime *rt) -{ - pmf_gpio_all_amps_off(rt); - rt->implementation_private = 0; - - if (rt->headphone_notify.gpio_private) - pmf_unregister_irq_client(rt->headphone_notify.gpio_private); - if (rt->line_in_notify.gpio_private) - pmf_unregister_irq_client(rt->line_in_notify.gpio_private); - if (rt->line_out_notify.gpio_private) - pmf_unregister_irq_client(rt->line_out_notify.gpio_private); - - /* make sure no work is pending before freeing - * all things */ - cancel_delayed_work_sync(&rt->headphone_notify.work); - cancel_delayed_work_sync(&rt->line_in_notify.work); - cancel_delayed_work_sync(&rt->line_out_notify.work); - - mutex_destroy(&rt->headphone_notify.mutex); - mutex_destroy(&rt->line_in_notify.mutex); - mutex_destroy(&rt->line_out_notify.mutex); - - kfree(rt->headphone_notify.gpio_private); - kfree(rt->line_in_notify.gpio_private); - kfree(rt->line_out_notify.gpio_private); -} - -static void pmf_handle_notify_irq(void *data) -{ - struct gpio_notification *notif = data; - - schedule_delayed_work(¬if->work, 0); -} - -static int pmf_set_notify(struct gpio_runtime *rt, - enum notify_type type, - notify_func_t notify, - void *data) -{ - struct gpio_notification *notif; - notify_func_t old; - struct pmf_irq_client *irq_client; - char *name; - int err = -EBUSY; - - switch (type) { - case AOA_NOTIFY_HEADPHONE: - notif = &rt->headphone_notify; - name = "headphone-detect"; - break; - case AOA_NOTIFY_LINE_IN: - notif = &rt->line_in_notify; - name = "linein-detect"; - break; - case AOA_NOTIFY_LINE_OUT: - notif = &rt->line_out_notify; - name = "lineout-detect"; - break; - default: - return -EINVAL; - } - - mutex_lock(¬if->mutex); - - old = notif->notify; - - if (!old && !notify) { - err = 0; - goto out_unlock; - } - - if (old && notify) { - if (old == notify && notif->data == data) - err = 0; - goto out_unlock; - } - - if (old && !notify) { - irq_client = notif->gpio_private; - pmf_unregister_irq_client(irq_client); - kfree(irq_client); - notif->gpio_private = NULL; - } - if (!old && notify) { - irq_client = kzalloc(sizeof(struct pmf_irq_client), - GFP_KERNEL); - if (!irq_client) { - err = -ENOMEM; - goto out_unlock; - } - irq_client->data = notif; - irq_client->handler = pmf_handle_notify_irq; - irq_client->owner = THIS_MODULE; - err = pmf_register_irq_client(rt->node, - name, - irq_client); - if (err) { - printk(KERN_ERR "snd-aoa: gpio layer failed to" - " register %s irq (%d)\n", name, err); - kfree(irq_client); - goto out_unlock; - } - notif->gpio_private = irq_client; - } - notif->notify = notify; - notif->data = data; - - err = 0; - out_unlock: - mutex_unlock(¬if->mutex); - return err; -} - -static int pmf_get_detect(struct gpio_runtime *rt, - enum notify_type type) -{ - char *name; - int err = -EBUSY, ret; - struct pmf_args args = { .count = 1, .u[0].p = &ret }; - - switch (type) { - case AOA_NOTIFY_HEADPHONE: - name = "headphone-detect"; - break; - case AOA_NOTIFY_LINE_IN: - name = "linein-detect"; - break; - case AOA_NOTIFY_LINE_OUT: - name = "lineout-detect"; - break; - default: - return -EINVAL; - } - - err = pmf_call_function(rt->node, name, &args); - if (err) - return err; - return ret; -} - -static struct gpio_methods methods = { - .init = pmf_gpio_init, - .exit = pmf_gpio_exit, - .all_amps_off = pmf_gpio_all_amps_off, - .all_amps_restore = pmf_gpio_all_amps_restore, - .set_headphone = pmf_gpio_set_headphone, - .set_speakers = pmf_gpio_set_amp, - .set_lineout = pmf_gpio_set_lineout, - .set_hw_reset = pmf_gpio_set_hw_reset, - .get_headphone = pmf_gpio_get_headphone, - .get_speakers = pmf_gpio_get_amp, - .get_lineout = pmf_gpio_get_lineout, - .set_notify = pmf_set_notify, - .get_detect = pmf_get_detect, -}; - -struct gpio_methods *pmf_gpio_methods = &methods; -EXPORT_SYMBOL_GPL(pmf_gpio_methods); diff --git a/ANDROID_3.4.5/sound/aoa/fabrics/Kconfig b/ANDROID_3.4.5/sound/aoa/fabrics/Kconfig deleted file mode 100644 index 3ca475a8..00000000 --- a/ANDROID_3.4.5/sound/aoa/fabrics/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config SND_AOA_FABRIC_LAYOUT - tristate "layout-id fabric" - select SND_AOA_SOUNDBUS - select SND_AOA_SOUNDBUS_I2S - ---help--- - This enables the layout-id fabric for the Apple Onboard - Audio driver, the module holding it all together - based on the device-tree's layout-id property. - - If you are unsure and have a later Apple machine, - compile it as a module. diff --git a/ANDROID_3.4.5/sound/aoa/fabrics/Makefile b/ANDROID_3.4.5/sound/aoa/fabrics/Makefile deleted file mode 100644 index da37c10e..00000000 --- a/ANDROID_3.4.5/sound/aoa/fabrics/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -snd-aoa-fabric-layout-objs += layout.o - -obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o diff --git a/ANDROID_3.4.5/sound/aoa/fabrics/layout.c b/ANDROID_3.4.5/sound/aoa/fabrics/layout.c deleted file mode 100644 index 552b97af..00000000 --- a/ANDROID_3.4.5/sound/aoa/fabrics/layout.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* - * Apple Onboard Audio driver -- layout/machine id fabric - * - * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - * - * - * This fabric module looks for sound codecs based on the - * layout-id or device-id property in the device tree. - */ -#include <asm/prom.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/slab.h> -#include "../aoa.h" -#include "../soundbus/soundbus.h" - -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa"); - -#define MAX_CODECS_PER_BUS 2 - -/* These are the connections the layout fabric - * knows about. It doesn't really care about the - * input ones, but I thought I'd separate them - * to give them proper names. The thing is that - * Apple usually will distinguish the active output - * by GPIOs, while the active input is set directly - * on the codec. Hence we here tell the codec what - * we think is connected. This information is hard- - * coded below ... */ -#define CC_SPEAKERS (1<<0) -#define CC_HEADPHONE (1<<1) -#define CC_LINEOUT (1<<2) -#define CC_DIGITALOUT (1<<3) -#define CC_LINEIN (1<<4) -#define CC_MICROPHONE (1<<5) -#define CC_DIGITALIN (1<<6) -/* pretty bogus but users complain... - * This is a flag saying that the LINEOUT - * should be renamed to HEADPHONE. - * be careful with input detection! */ -#define CC_LINEOUT_LABELLED_HEADPHONE (1<<7) - -struct codec_connection { - /* CC_ flags from above */ - int connected; - /* codec dependent bit to be set in the aoa_codec.connected field. - * This intentionally doesn't have any generic flags because the - * fabric has to know the codec anyway and all codecs might have - * different connectors */ - int codec_bit; -}; - -struct codec_connect_info { - char *name; - struct codec_connection *connections; -}; - -#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0) - -struct layout { - unsigned int layout_id, device_id; - struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; - int flags; - - /* if busname is not assigned, we use 'Master' below, - * so that our layout table doesn't need to be filled - * too much. - * We only assign these two if we expect to find more - * than one soundbus, i.e. on those machines with - * multiple layout-ids */ - char *busname; - int pcmid; -}; - -MODULE_ALIAS("sound-layout-36"); -MODULE_ALIAS("sound-layout-41"); -MODULE_ALIAS("sound-layout-45"); -MODULE_ALIAS("sound-layout-47"); -MODULE_ALIAS("sound-layout-48"); -MODULE_ALIAS("sound-layout-49"); -MODULE_ALIAS("sound-layout-50"); -MODULE_ALIAS("sound-layout-51"); -MODULE_ALIAS("sound-layout-56"); -MODULE_ALIAS("sound-layout-57"); -MODULE_ALIAS("sound-layout-58"); -MODULE_ALIAS("sound-layout-60"); -MODULE_ALIAS("sound-layout-61"); -MODULE_ALIAS("sound-layout-62"); -MODULE_ALIAS("sound-layout-64"); -MODULE_ALIAS("sound-layout-65"); -MODULE_ALIAS("sound-layout-66"); -MODULE_ALIAS("sound-layout-67"); -MODULE_ALIAS("sound-layout-68"); -MODULE_ALIAS("sound-layout-69"); -MODULE_ALIAS("sound-layout-70"); -MODULE_ALIAS("sound-layout-72"); -MODULE_ALIAS("sound-layout-76"); -MODULE_ALIAS("sound-layout-80"); -MODULE_ALIAS("sound-layout-82"); -MODULE_ALIAS("sound-layout-84"); -MODULE_ALIAS("sound-layout-86"); -MODULE_ALIAS("sound-layout-90"); -MODULE_ALIAS("sound-layout-92"); -MODULE_ALIAS("sound-layout-94"); -MODULE_ALIAS("sound-layout-96"); -MODULE_ALIAS("sound-layout-98"); -MODULE_ALIAS("sound-layout-100"); - -MODULE_ALIAS("aoa-device-id-14"); -MODULE_ALIAS("aoa-device-id-22"); -MODULE_ALIAS("aoa-device-id-35"); - -/* onyx with all but microphone connected */ -static struct codec_connection onyx_connections_nomic[] = { - { - .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, - .codec_bit = 0, - }, - { - .connected = CC_DIGITALOUT, - .codec_bit = 1, - }, - { - .connected = CC_LINEIN, - .codec_bit = 2, - }, - {} /* terminate array by .connected == 0 */ -}; - -/* onyx on machines without headphone */ -static struct codec_connection onyx_connections_noheadphones[] = { - { - .connected = CC_SPEAKERS | CC_LINEOUT | - CC_LINEOUT_LABELLED_HEADPHONE, - .codec_bit = 0, - }, - { - .connected = CC_DIGITALOUT, - .codec_bit = 1, - }, - /* FIXME: are these correct? probably not for all the machines - * below ... If not this will need separating. */ - { - .connected = CC_LINEIN, - .codec_bit = 2, - }, - { - .connected = CC_MICROPHONE, - .codec_bit = 3, - }, - {} /* terminate array by .connected == 0 */ -}; - -/* onyx on machines with real line-out */ -static struct codec_connection onyx_connections_reallineout[] = { - { - .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE, - .codec_bit = 0, - }, - { - .connected = CC_DIGITALOUT, - .codec_bit = 1, - }, - { - .connected = CC_LINEIN, - .codec_bit = 2, - }, - {} /* terminate array by .connected == 0 */ -}; - -/* tas on machines without line out */ -static struct codec_connection tas_connections_nolineout[] = { - { - .connected = CC_SPEAKERS | CC_HEADPHONE, - .codec_bit = 0, - }, - { - .connected = CC_LINEIN, - .codec_bit = 2, - }, - { - .connected = CC_MICROPHONE, - .codec_bit = 3, - }, - {} /* terminate array by .connected == 0 */ -}; - -/* tas on machines with neither line out nor line in */ -static struct codec_connection tas_connections_noline[] = { - { - .connected = CC_SPEAKERS | CC_HEADPHONE, - .codec_bit = 0, - }, - { - .connected = CC_MICROPHONE, - .codec_bit = 3, - }, - {} /* terminate array by .connected == 0 */ -}; - -/* tas on machines without microphone */ -static struct codec_connection tas_connections_nomic[] = { - { - .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, - .codec_bit = 0, - }, - { - .connected = CC_LINEIN, - .codec_bit = 2, - }, - {} /* terminate array by .connected == 0 */ -}; - -/* tas on machines with everything connected */ -static struct codec_connection tas_connections_all[] = { - { - .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, - .codec_bit = 0, - }, - { - .connected = CC_LINEIN, - .codec_bit = 2, - }, - { - .connected = CC_MICROPHONE, - .codec_bit = 3, - }, - {} /* terminate array by .connected == 0 */ -}; - -static struct codec_connection toonie_connections[] = { - { - .connected = CC_SPEAKERS | CC_HEADPHONE, - .codec_bit = 0, - }, - {} /* terminate array by .connected == 0 */ -}; - -static struct codec_connection topaz_input[] = { - { - .connected = CC_DIGITALIN, - .codec_bit = 0, - }, - {} /* terminate array by .connected == 0 */ -}; - -static struct codec_connection topaz_output[] = { - { - .connected = CC_DIGITALOUT, - .codec_bit = 1, - }, - {} /* terminate array by .connected == 0 */ -}; - -static struct codec_connection topaz_inout[] = { - { - .connected = CC_DIGITALIN, - .codec_bit = 0, - }, - { - .connected = CC_DIGITALOUT, - .codec_bit = 1, - }, - {} /* terminate array by .connected == 0 */ -}; - -static struct layout layouts[] = { - /* last PowerBooks (15" Oct 2005) */ - { .layout_id = 82, - .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - /* PowerMac9,1 */ - { .layout_id = 60, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_reallineout, - }, - }, - /* PowerMac9,1 */ - { .layout_id = 61, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - /* PowerBook5,7 */ - { .layout_id = 64, - .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - }, - /* PowerBook5,7 */ - { .layout_id = 65, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - /* PowerBook5,9 [17" Oct 2005] */ - { .layout_id = 84, - .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - /* PowerMac8,1 */ - { .layout_id = 45, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - /* Quad PowerMac (analog in, analog/digital out) */ - { .layout_id = 68, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_nomic, - }, - }, - /* Quad PowerMac (digital in) */ - { .layout_id = 69, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - .busname = "digital in", .pcmid = 1 }, - /* Early 2005 PowerBook (PowerBook 5,6) */ - { .layout_id = 70, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_nolineout, - }, - }, - /* PowerBook 5,4 */ - { .layout_id = 51, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_nolineout, - }, - }, - /* PowerBook6,7 */ - { .layout_id = 80, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_noline, - }, - }, - /* PowerBook6,8 */ - { .layout_id = 72, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_nolineout, - }, - }, - /* PowerMac8,2 */ - { .layout_id = 86, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_nomic, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - /* PowerBook6,7 */ - { .layout_id = 92, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_nolineout, - }, - }, - /* PowerMac10,1 (Mac Mini) */ - { .layout_id = 58, - .codecs[0] = { - .name = "toonie", - .connections = toonie_connections, - }, - }, - { - .layout_id = 96, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - }, - /* unknown, untested, but this comes from Apple */ - { .layout_id = 41, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_all, - }, - }, - { .layout_id = 36, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_nomic, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_inout, - }, - }, - { .layout_id = 47, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - }, - { .layout_id = 48, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - { .layout_id = 49, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_nomic, - }, - }, - { .layout_id = 50, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - { .layout_id = 56, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - }, - { .layout_id = 57, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - { .layout_id = 62, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_output, - }, - }, - { .layout_id = 66, - .codecs[0] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - }, - { .layout_id = 67, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - }, - { .layout_id = 76, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_nomic, - }, - .codecs[1] = { - .name = "topaz", - .connections = topaz_inout, - }, - }, - { .layout_id = 90, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_noline, - }, - }, - { .layout_id = 94, - .codecs[0] = { - .name = "onyx", - /* but it has an external mic?? how to select? */ - .connections = onyx_connections_noheadphones, - }, - }, - { .layout_id = 98, - .codecs[0] = { - .name = "toonie", - .connections = toonie_connections, - }, - }, - { .layout_id = 100, - .codecs[0] = { - .name = "topaz", - .connections = topaz_input, - }, - .codecs[1] = { - .name = "onyx", - .connections = onyx_connections_noheadphones, - }, - }, - /* PowerMac3,4 */ - { .device_id = 14, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_noline, - }, - }, - /* PowerMac3,6 */ - { .device_id = 22, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_all, - }, - }, - /* PowerBook5,2 */ - { .device_id = 35, - .codecs[0] = { - .name = "tas", - .connections = tas_connections_all, - }, - }, - {} -}; - -static struct layout *find_layout_by_id(unsigned int id) -{ - struct layout *l; - - l = layouts; - while (l->codecs[0].name) { - if (l->layout_id == id) - return l; - l++; - } - return NULL; -} - -static struct layout *find_layout_by_device(unsigned int id) -{ - struct layout *l; - - l = layouts; - while (l->codecs[0].name) { - if (l->device_id == id) - return l; - l++; - } - return NULL; -} - -static void use_layout(struct layout *l) -{ - int i; - - for (i=0; i<MAX_CODECS_PER_BUS; i++) { - if (l->codecs[i].name) { - request_module("snd-aoa-codec-%s", l->codecs[i].name); - } - } - /* now we wait for the codecs to call us back */ -} - -struct layout_dev; - -struct layout_dev_ptr { - struct layout_dev *ptr; -}; - -struct layout_dev { - struct list_head list; - struct soundbus_dev *sdev; - struct device_node *sound; - struct aoa_codec *codecs[MAX_CODECS_PER_BUS]; - struct layout *layout; - struct gpio_runtime gpio; - - /* we need these for headphone/lineout detection */ - struct snd_kcontrol *headphone_ctrl; - struct snd_kcontrol *lineout_ctrl; - struct snd_kcontrol *speaker_ctrl; - struct snd_kcontrol *master_ctrl; - struct snd_kcontrol *headphone_detected_ctrl; - struct snd_kcontrol *lineout_detected_ctrl; - - struct layout_dev_ptr selfptr_headphone; - struct layout_dev_ptr selfptr_lineout; - - u32 have_lineout_detect:1, - have_headphone_detect:1, - switch_on_headphone:1, - switch_on_lineout:1; -}; - -static LIST_HEAD(layouts_list); -static int layouts_list_items; -/* this can go away but only if we allow multiple cards, - * make the fabric handle all the card stuff, etc... */ -static struct layout_dev *layout_device; - -#define control_info snd_ctl_boolean_mono_info - -#define AMP_CONTROL(n, description) \ -static int n##_control_get(struct snd_kcontrol *kcontrol, \ - struct snd_ctl_elem_value *ucontrol) \ -{ \ - struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ - if (gpio->methods && gpio->methods->get_##n) \ - ucontrol->value.integer.value[0] = \ - gpio->methods->get_##n(gpio); \ - return 0; \ -} \ -static int n##_control_put(struct snd_kcontrol *kcontrol, \ - struct snd_ctl_elem_value *ucontrol) \ -{ \ - struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ - if (gpio->methods && gpio->methods->get_##n) \ - gpio->methods->set_##n(gpio, \ - !!ucontrol->value.integer.value[0]); \ - return 1; \ -} \ -static struct snd_kcontrol_new n##_ctl = { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = description, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = control_info, \ - .get = n##_control_get, \ - .put = n##_control_put, \ -} - -AMP_CONTROL(headphone, "Headphone Switch"); -AMP_CONTROL(speakers, "Speakers Switch"); -AMP_CONTROL(lineout, "Line-Out Switch"); -AMP_CONTROL(master, "Master Switch"); - -static int detect_choice_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); - - switch (kcontrol->private_value) { - case 0: - ucontrol->value.integer.value[0] = ldev->switch_on_headphone; - break; - case 1: - ucontrol->value.integer.value[0] = ldev->switch_on_lineout; - break; - default: - return -ENODEV; - } - return 0; -} - -static int detect_choice_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); - - switch (kcontrol->private_value) { - case 0: - ldev->switch_on_headphone = !!ucontrol->value.integer.value[0]; - break; - case 1: - ldev->switch_on_lineout = !!ucontrol->value.integer.value[0]; - break; - default: - return -ENODEV; - } - return 1; -} - -static struct snd_kcontrol_new headphone_detect_choice = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Headphone Detect Autoswitch", - .info = control_info, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .get = detect_choice_get, - .put = detect_choice_put, - .private_value = 0, -}; - -static struct snd_kcontrol_new lineout_detect_choice = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-Out Detect Autoswitch", - .info = control_info, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .get = detect_choice_get, - .put = detect_choice_put, - .private_value = 1, -}; - -static int detected_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); - int v; - - switch (kcontrol->private_value) { - case 0: - v = ldev->gpio.methods->get_detect(&ldev->gpio, - AOA_NOTIFY_HEADPHONE); - break; - case 1: - v = ldev->gpio.methods->get_detect(&ldev->gpio, - AOA_NOTIFY_LINE_OUT); - break; - default: - return -ENODEV; - } - ucontrol->value.integer.value[0] = v; - return 0; -} - -static struct snd_kcontrol_new headphone_detected = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Headphone Detected", - .info = control_info, - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .get = detected_get, - .private_value = 0, -}; - -static struct snd_kcontrol_new lineout_detected = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-Out Detected", - .info = control_info, - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .get = detected_get, - .private_value = 1, -}; - -static int check_codec(struct aoa_codec *codec, - struct layout_dev *ldev, - struct codec_connect_info *cci) -{ - const u32 *ref; - char propname[32]; - struct codec_connection *cc; - - /* if the codec has a 'codec' node, we require a reference */ - if (codec->node && (strcmp(codec->node->name, "codec") == 0)) { - snprintf(propname, sizeof(propname), - "platform-%s-codec-ref", codec->name); - ref = of_get_property(ldev->sound, propname, NULL); - if (!ref) { - printk(KERN_INFO "snd-aoa-fabric-layout: " - "required property %s not present\n", propname); - return -ENODEV; - } - if (*ref != codec->node->phandle) { - printk(KERN_INFO "snd-aoa-fabric-layout: " - "%s doesn't match!\n", propname); - return -ENODEV; - } - } else { - if (layouts_list_items != 1) { - printk(KERN_INFO "snd-aoa-fabric-layout: " - "more than one soundbus, but no references.\n"); - return -ENODEV; - } - } - codec->soundbus_dev = ldev->sdev; - codec->gpio = &ldev->gpio; - - cc = cci->connections; - if (!cc) - return -EINVAL; - - printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n"); - - codec->connected = 0; - codec->fabric_data = cc; - - while (cc->connected) { - codec->connected |= 1<<cc->codec_bit; - cc++; - } - - return 0; -} - -static int layout_found_codec(struct aoa_codec *codec) -{ - struct layout_dev *ldev; - int i; - - list_for_each_entry(ldev, &layouts_list, list) { - for (i=0; i<MAX_CODECS_PER_BUS; i++) { - if (!ldev->layout->codecs[i].name) - continue; - if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) { - if (check_codec(codec, - ldev, - &ldev->layout->codecs[i]) == 0) - return 0; - } - } - } - return -ENODEV; -} - -static void layout_remove_codec(struct aoa_codec *codec) -{ - int i; - /* here remove the codec from the layout dev's - * codec reference */ - - codec->soundbus_dev = NULL; - codec->gpio = NULL; - for (i=0; i<MAX_CODECS_PER_BUS; i++) { - } -} - -static void layout_notify(void *data) -{ - struct layout_dev_ptr *dptr = data; - struct layout_dev *ldev; - int v, update; - struct snd_kcontrol *detected, *c; - struct snd_card *card = aoa_get_card(); - - ldev = dptr->ptr; - if (data == &ldev->selfptr_headphone) { - v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE); - detected = ldev->headphone_detected_ctrl; - update = ldev->switch_on_headphone; - if (update) { - ldev->gpio.methods->set_speakers(&ldev->gpio, !v); - ldev->gpio.methods->set_headphone(&ldev->gpio, v); - ldev->gpio.methods->set_lineout(&ldev->gpio, 0); - } - } else if (data == &ldev->selfptr_lineout) { - v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT); - detected = ldev->lineout_detected_ctrl; - update = ldev->switch_on_lineout; - if (update) { - ldev->gpio.methods->set_speakers(&ldev->gpio, !v); - ldev->gpio.methods->set_headphone(&ldev->gpio, 0); - ldev->gpio.methods->set_lineout(&ldev->gpio, v); - } - } else - return; - - if (detected) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id); - if (update) { - c = ldev->headphone_ctrl; - if (c) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); - c = ldev->speaker_ctrl; - if (c) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); - c = ldev->lineout_ctrl; - if (c) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); - } -} - -static void layout_attached_codec(struct aoa_codec *codec) -{ - struct codec_connection *cc; - struct snd_kcontrol *ctl; - int headphones, lineout; - struct layout_dev *ldev = layout_device; - - /* need to add this codec to our codec array! */ - - cc = codec->fabric_data; - - headphones = codec->gpio->methods->get_detect(codec->gpio, - AOA_NOTIFY_HEADPHONE); - lineout = codec->gpio->methods->get_detect(codec->gpio, - AOA_NOTIFY_LINE_OUT); - - if (codec->gpio->methods->set_master) { - ctl = snd_ctl_new1(&master_ctl, codec->gpio); - ldev->master_ctrl = ctl; - aoa_snd_ctl_add(ctl); - } - while (cc->connected) { - if (cc->connected & CC_SPEAKERS) { - if (headphones <= 0 && lineout <= 0) - ldev->gpio.methods->set_speakers(codec->gpio, 1); - ctl = snd_ctl_new1(&speakers_ctl, codec->gpio); - ldev->speaker_ctrl = ctl; - aoa_snd_ctl_add(ctl); - } - if (cc->connected & CC_HEADPHONE) { - if (headphones == 1) - ldev->gpio.methods->set_headphone(codec->gpio, 1); - ctl = snd_ctl_new1(&headphone_ctl, codec->gpio); - ldev->headphone_ctrl = ctl; - aoa_snd_ctl_add(ctl); - ldev->have_headphone_detect = - !ldev->gpio.methods - ->set_notify(&ldev->gpio, - AOA_NOTIFY_HEADPHONE, - layout_notify, - &ldev->selfptr_headphone); - if (ldev->have_headphone_detect) { - ctl = snd_ctl_new1(&headphone_detect_choice, - ldev); - aoa_snd_ctl_add(ctl); - ctl = snd_ctl_new1(&headphone_detected, - ldev); - ldev->headphone_detected_ctrl = ctl; - aoa_snd_ctl_add(ctl); - } - } - if (cc->connected & CC_LINEOUT) { - if (lineout == 1) - ldev->gpio.methods->set_lineout(codec->gpio, 1); - ctl = snd_ctl_new1(&lineout_ctl, codec->gpio); - if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) - strlcpy(ctl->id.name, - "Headphone Switch", sizeof(ctl->id.name)); - ldev->lineout_ctrl = ctl; - aoa_snd_ctl_add(ctl); - ldev->have_lineout_detect = - !ldev->gpio.methods - ->set_notify(&ldev->gpio, - AOA_NOTIFY_LINE_OUT, - layout_notify, - &ldev->selfptr_lineout); - if (ldev->have_lineout_detect) { - ctl = snd_ctl_new1(&lineout_detect_choice, - ldev); - if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) - strlcpy(ctl->id.name, - "Headphone Detect Autoswitch", - sizeof(ctl->id.name)); - aoa_snd_ctl_add(ctl); - ctl = snd_ctl_new1(&lineout_detected, - ldev); - if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) - strlcpy(ctl->id.name, - "Headphone Detected", - sizeof(ctl->id.name)); - ldev->lineout_detected_ctrl = ctl; - aoa_snd_ctl_add(ctl); - } - } - cc++; - } - /* now update initial state */ - if (ldev->have_headphone_detect) - layout_notify(&ldev->selfptr_headphone); - if (ldev->have_lineout_detect) - layout_notify(&ldev->selfptr_lineout); -} - -static struct aoa_fabric layout_fabric = { - .name = "SoundByLayout", - .owner = THIS_MODULE, - .found_codec = layout_found_codec, - .remove_codec = layout_remove_codec, - .attached_codec = layout_attached_codec, -}; - -static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) -{ - struct device_node *sound = NULL; - const unsigned int *id; - struct layout *layout = NULL; - struct layout_dev *ldev = NULL; - int err; - - /* hm, currently we can only have one ... */ - if (layout_device) - return -ENODEV; - - /* by breaking out we keep a reference */ - while ((sound = of_get_next_child(sdev->ofdev.dev.of_node, sound))) { - if (sound->type && strcasecmp(sound->type, "soundchip") == 0) - break; - } - if (!sound) - return -ENODEV; - - id = of_get_property(sound, "layout-id", NULL); - if (id) { - layout = find_layout_by_id(*id); - } else { - id = of_get_property(sound, "device-id", NULL); - if (id) - layout = find_layout_by_device(*id); - } - - if (!layout) { - printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n"); - goto outnodev; - } - - ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL); - if (!ldev) - goto outnodev; - - layout_device = ldev; - ldev->sdev = sdev; - ldev->sound = sound; - ldev->layout = layout; - ldev->gpio.node = sound->parent; - switch (layout->layout_id) { - case 0: /* anything with device_id, not layout_id */ - case 41: /* that unknown machine no one seems to have */ - case 51: /* PowerBook5,4 */ - case 58: /* Mac Mini */ - ldev->gpio.methods = ftr_gpio_methods; - printk(KERN_DEBUG - "snd-aoa-fabric-layout: Using direct GPIOs\n"); - break; - default: - ldev->gpio.methods = pmf_gpio_methods; - printk(KERN_DEBUG - "snd-aoa-fabric-layout: Using PMF GPIOs\n"); - } - ldev->selfptr_headphone.ptr = ldev; - ldev->selfptr_lineout.ptr = ldev; - dev_set_drvdata(&sdev->ofdev.dev, ldev); - list_add(&ldev->list, &layouts_list); - layouts_list_items++; - - /* assign these before registering ourselves, so - * callbacks that are done during registration - * already have the values */ - sdev->pcmid = ldev->layout->pcmid; - if (ldev->layout->busname) { - sdev->pcmname = ldev->layout->busname; - } else { - sdev->pcmname = "Master"; - } - - ldev->gpio.methods->init(&ldev->gpio); - - err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev); - if (err && err != -EALREADY) { - printk(KERN_INFO "snd-aoa-fabric-layout: can't use," - " another fabric is active!\n"); - goto outlistdel; - } - - use_layout(layout); - ldev->switch_on_headphone = 1; - ldev->switch_on_lineout = 1; - return 0; - outlistdel: - /* we won't be using these then... */ - ldev->gpio.methods->exit(&ldev->gpio); - /* reset if we didn't use it */ - sdev->pcmname = NULL; - sdev->pcmid = -1; - list_del(&ldev->list); - layouts_list_items--; - kfree(ldev); - outnodev: - of_node_put(sound); - layout_device = NULL; - return -ENODEV; -} - -static int aoa_fabric_layout_remove(struct soundbus_dev *sdev) -{ - struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); - int i; - - for (i=0; i<MAX_CODECS_PER_BUS; i++) { - if (ldev->codecs[i]) { - aoa_fabric_unlink_codec(ldev->codecs[i]); - } - ldev->codecs[i] = NULL; - } - list_del(&ldev->list); - layouts_list_items--; - of_node_put(ldev->sound); - - ldev->gpio.methods->set_notify(&ldev->gpio, - AOA_NOTIFY_HEADPHONE, - NULL, - NULL); - ldev->gpio.methods->set_notify(&ldev->gpio, - AOA_NOTIFY_LINE_OUT, - NULL, - NULL); - - ldev->gpio.methods->exit(&ldev->gpio); - layout_device = NULL; - kfree(ldev); - sdev->pcmid = -1; - sdev->pcmname = NULL; - return 0; -} - -#ifdef CONFIG_PM -static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state) -{ - struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); - - if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) - ldev->gpio.methods->all_amps_off(&ldev->gpio); - - return 0; -} - -static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) -{ - struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); - - if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) - ldev->gpio.methods->all_amps_restore(&ldev->gpio); - - return 0; -} -#endif - -static struct soundbus_driver aoa_soundbus_driver = { - .name = "snd_aoa_soundbus_drv", - .owner = THIS_MODULE, - .probe = aoa_fabric_layout_probe, - .remove = aoa_fabric_layout_remove, -#ifdef CONFIG_PM - .suspend = aoa_fabric_layout_suspend, - .resume = aoa_fabric_layout_resume, -#endif - .driver = { - .owner = THIS_MODULE, - } -}; - -static int __init aoa_fabric_layout_init(void) -{ - int err; - - err = soundbus_register_driver(&aoa_soundbus_driver); - if (err) - return err; - return 0; -} - -static void __exit aoa_fabric_layout_exit(void) -{ - soundbus_unregister_driver(&aoa_soundbus_driver); - aoa_fabric_unregister(&layout_fabric); -} - -module_init(aoa_fabric_layout_init); -module_exit(aoa_fabric_layout_exit); diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/Kconfig b/ANDROID_3.4.5/sound/aoa/soundbus/Kconfig deleted file mode 100644 index 839d1137..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config SND_AOA_SOUNDBUS - tristate "Apple Soundbus support" - select SND_PCM - ---help--- - This option enables the generic driver for the soundbus - support on Apple machines. - - It is required for the sound bus implementations. - -config SND_AOA_SOUNDBUS_I2S - tristate "I2S bus support" - depends on SND_AOA_SOUNDBUS && PCI - ---help--- - This option enables support for Apple I2S busses. diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/Makefile b/ANDROID_3.4.5/sound/aoa/soundbus/Makefile deleted file mode 100644 index 0e61f5aa..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_SND_AOA_SOUNDBUS) += snd-aoa-soundbus.o -snd-aoa-soundbus-objs := core.o sysfs.o -obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += i2sbus/ diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/core.c b/ANDROID_3.4.5/sound/aoa/soundbus/core.c deleted file mode 100644 index 7487eb76..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/core.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * soundbus - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#include <linux/module.h> -#include "soundbus.h" - -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Apple Soundbus"); - -struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev) -{ - struct device *tmp; - - if (!dev) - return NULL; - tmp = get_device(&dev->ofdev.dev); - if (tmp) - return to_soundbus_device(tmp); - else - return NULL; -} -EXPORT_SYMBOL_GPL(soundbus_dev_get); - -void soundbus_dev_put(struct soundbus_dev *dev) -{ - if (dev) - put_device(&dev->ofdev.dev); -} -EXPORT_SYMBOL_GPL(soundbus_dev_put); - -static int soundbus_probe(struct device *dev) -{ - int error = -ENODEV; - struct soundbus_driver *drv; - struct soundbus_dev *soundbus_dev; - - drv = to_soundbus_driver(dev->driver); - soundbus_dev = to_soundbus_device(dev); - - if (!drv->probe) - return error; - - soundbus_dev_get(soundbus_dev); - - error = drv->probe(soundbus_dev); - if (error) - soundbus_dev_put(soundbus_dev); - - return error; -} - - -static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct soundbus_dev * soundbus_dev; - struct platform_device * of; - const char *compat; - int retval = 0; - int cplen, seen = 0; - - if (!dev) - return -ENODEV; - - soundbus_dev = to_soundbus_device(dev); - if (!soundbus_dev) - return -ENODEV; - - of = &soundbus_dev->ofdev; - - /* stuff we want to pass to /sbin/hotplug */ - retval = add_uevent_var(env, "OF_NAME=%s", of->dev.of_node->name); - if (retval) - return retval; - - retval = add_uevent_var(env, "OF_TYPE=%s", of->dev.of_node->type); - if (retval) - return retval; - - /* Since the compatible field can contain pretty much anything - * it's not really legal to split it out with commas. We split it - * up using a number of environment variables instead. */ - - compat = of_get_property(of->dev.of_node, "compatible", &cplen); - while (compat && cplen > 0) { - int tmp = env->buflen; - retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); - if (retval) - return retval; - compat += env->buflen - tmp; - cplen -= env->buflen - tmp; - seen += 1; - } - - retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); - if (retval) - return retval; - retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias); - - return retval; -} - -static int soundbus_device_remove(struct device *dev) -{ - struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); - struct soundbus_driver * drv = to_soundbus_driver(dev->driver); - - if (dev->driver && drv->remove) - drv->remove(soundbus_dev); - soundbus_dev_put(soundbus_dev); - - return 0; -} - -static void soundbus_device_shutdown(struct device *dev) -{ - struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); - struct soundbus_driver * drv = to_soundbus_driver(dev->driver); - - if (dev->driver && drv->shutdown) - drv->shutdown(soundbus_dev); -} - -#ifdef CONFIG_PM - -static int soundbus_device_suspend(struct device *dev, pm_message_t state) -{ - struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); - struct soundbus_driver * drv = to_soundbus_driver(dev->driver); - - if (dev->driver && drv->suspend) - return drv->suspend(soundbus_dev, state); - return 0; -} - -static int soundbus_device_resume(struct device * dev) -{ - struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); - struct soundbus_driver * drv = to_soundbus_driver(dev->driver); - - if (dev->driver && drv->resume) - return drv->resume(soundbus_dev); - return 0; -} - -#endif /* CONFIG_PM */ - -static struct bus_type soundbus_bus_type = { - .name = "aoa-soundbus", - .probe = soundbus_probe, - .uevent = soundbus_uevent, - .remove = soundbus_device_remove, - .shutdown = soundbus_device_shutdown, -#ifdef CONFIG_PM - .suspend = soundbus_device_suspend, - .resume = soundbus_device_resume, -#endif - .dev_attrs = soundbus_dev_attrs, -}; - -int soundbus_add_one(struct soundbus_dev *dev) -{ - static int devcount; - - /* sanity checks */ - if (!dev->attach_codec || - !dev->ofdev.dev.of_node || - dev->pcmname || - dev->pcmid != -1) { - printk(KERN_ERR "soundbus: adding device failed sanity check!\n"); - return -EINVAL; - } - - dev_set_name(&dev->ofdev.dev, "soundbus:%x", ++devcount); - dev->ofdev.dev.bus = &soundbus_bus_type; - return of_device_register(&dev->ofdev); -} -EXPORT_SYMBOL_GPL(soundbus_add_one); - -void soundbus_remove_one(struct soundbus_dev *dev) -{ - of_device_unregister(&dev->ofdev); -} -EXPORT_SYMBOL_GPL(soundbus_remove_one); - -int soundbus_register_driver(struct soundbus_driver *drv) -{ - /* initialize common driver fields */ - drv->driver.name = drv->name; - drv->driver.bus = &soundbus_bus_type; - - /* register with core */ - return driver_register(&drv->driver); -} -EXPORT_SYMBOL_GPL(soundbus_register_driver); - -void soundbus_unregister_driver(struct soundbus_driver *drv) -{ - driver_unregister(&drv->driver); -} -EXPORT_SYMBOL_GPL(soundbus_unregister_driver); - -static int __init soundbus_init(void) -{ - return bus_register(&soundbus_bus_type); -} - -static void __exit soundbus_exit(void) -{ - bus_unregister(&soundbus_bus_type); -} - -subsys_initcall(soundbus_init); -module_exit(soundbus_exit); diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile deleted file mode 100644 index 1b949b2a..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o -snd-aoa-i2sbus-objs := core.o pcm.o control.o diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c deleted file mode 100644 index 4dc9b49c..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * i2sbus driver -- bus control routines - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/macio.h> -#include <asm/pmac_feature.h> -#include <asm/pmac_pfunc.h> -#include <asm/keylargo.h> - -#include "i2sbus.h" - -int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) -{ - *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL); - if (!*c) - return -ENOMEM; - - INIT_LIST_HEAD(&(*c)->list); - - (*c)->macio = dev->bus->chip; - return 0; -} - -void i2sbus_control_destroy(struct i2sbus_control *c) -{ - kfree(c); -} - -/* this is serialised externally */ -int i2sbus_control_add_dev(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev) -{ - struct device_node *np; - - np = i2sdev->sound.ofdev.dev.of_node; - i2sdev->enable = pmf_find_function(np, "enable"); - i2sdev->cell_enable = pmf_find_function(np, "cell-enable"); - i2sdev->clock_enable = pmf_find_function(np, "clock-enable"); - i2sdev->cell_disable = pmf_find_function(np, "cell-disable"); - i2sdev->clock_disable = pmf_find_function(np, "clock-disable"); - - /* if the bus number is not 0 or 1 we absolutely need to use - * the platform functions -- there's nothing in Darwin that - * would allow seeing a system behind what the FCRs are then, - * and I don't want to go parsing a bunch of platform functions - * by hand to try finding a system... */ - if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 && - (!i2sdev->enable || - !i2sdev->cell_enable || !i2sdev->clock_enable || - !i2sdev->cell_disable || !i2sdev->clock_disable)) { - pmf_put_function(i2sdev->enable); - pmf_put_function(i2sdev->cell_enable); - pmf_put_function(i2sdev->clock_enable); - pmf_put_function(i2sdev->cell_disable); - pmf_put_function(i2sdev->clock_disable); - return -ENODEV; - } - - list_add(&i2sdev->item, &c->list); - - return 0; -} - -void i2sbus_control_remove_dev(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev) -{ - /* this is serialised externally */ - list_del(&i2sdev->item); - if (list_empty(&c->list)) - i2sbus_control_destroy(c); -} - -int i2sbus_control_enable(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev) -{ - struct pmf_args args = { .count = 0 }; - struct macio_chip *macio = c->macio; - - if (i2sdev->enable) - return pmf_call_one(i2sdev->enable, &args); - - if (macio == NULL || macio->base == NULL) - return -ENODEV; - - switch (i2sdev->bus_number) { - case 0: - /* these need to be locked or done through - * newly created feature calls! */ - MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE); - break; - case 1: - MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_ENABLE); - break; - default: - return -ENODEV; - } - return 0; -} - -int i2sbus_control_cell(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev, - int enable) -{ - struct pmf_args args = { .count = 0 }; - struct macio_chip *macio = c->macio; - - switch (enable) { - case 0: - if (i2sdev->cell_disable) - return pmf_call_one(i2sdev->cell_disable, &args); - break; - case 1: - if (i2sdev->cell_enable) - return pmf_call_one(i2sdev->cell_enable, &args); - break; - default: - printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n"); - return -ENODEV; - } - - if (macio == NULL || macio->base == NULL) - return -ENODEV; - - switch (i2sdev->bus_number) { - case 0: - if (enable) - MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); - else - MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); - break; - case 1: - if (enable) - MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); - else - MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); - break; - default: - return -ENODEV; - } - return 0; -} - -int i2sbus_control_clock(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev, - int enable) -{ - struct pmf_args args = { .count = 0 }; - struct macio_chip *macio = c->macio; - - switch (enable) { - case 0: - if (i2sdev->clock_disable) - return pmf_call_one(i2sdev->clock_disable, &args); - break; - case 1: - if (i2sdev->clock_enable) - return pmf_call_one(i2sdev->clock_enable, &args); - break; - default: - printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n"); - return -ENODEV; - } - - if (macio == NULL || macio->base == NULL) - return -ENODEV; - - switch (i2sdev->bus_number) { - case 0: - if (enable) - MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); - else - MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); - break; - case 1: - if (enable) - MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT); - else - MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT); - break; - default: - return -ENODEV; - } - return 0; -} diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c deleted file mode 100644 index 01065833..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * i2sbus driver - * - * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> - -#include <sound/core.h> - -#include <asm/macio.h> -#include <asm/dbdma.h> - -#include "../soundbus.h" -#include "i2sbus.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_DESCRIPTION("Apple Soundbus: I2S support"); - -static int force; -module_param(force, int, 0444); -MODULE_PARM_DESC(force, "Force loading i2sbus even when" - " no layout-id property is present"); - -static struct of_device_id i2sbus_match[] = { - { .name = "i2s" }, - { } -}; - -MODULE_DEVICE_TABLE(of, i2sbus_match); - -static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, - struct dbdma_command_mem *r, - int numcmds) -{ - /* one more for rounding, one for branch back, one for stop command */ - r->size = (numcmds + 3) * sizeof(struct dbdma_cmd); - /* We use the PCI APIs for now until the generic one gets fixed - * enough or until we get some macio-specific versions - */ - r->space = dma_alloc_coherent( - &macio_get_pci_dev(i2sdev->macio)->dev, - r->size, - &r->bus_addr, - GFP_KERNEL); - - if (!r->space) return -ENOMEM; - - memset(r->space, 0, r->size); - r->cmds = (void*)DBDMA_ALIGN(r->space); - r->bus_cmd_start = r->bus_addr + - (dma_addr_t)((char*)r->cmds - (char*)r->space); - - return 0; -} - -static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, - struct dbdma_command_mem *r) -{ - if (!r->space) return; - - dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, - r->size, r->space, r->bus_addr); -} - -static void i2sbus_release_dev(struct device *dev) -{ - struct i2sbus_dev *i2sdev; - int i; - - i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev); - - if (i2sdev->intfregs) iounmap(i2sdev->intfregs); - if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); - if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); - for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) - if (i2sdev->allocated_resource[i]) - release_and_free_resource(i2sdev->allocated_resource[i]); - free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); - free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring); - for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) - free_irq(i2sdev->interrupts[i], i2sdev); - i2sbus_control_remove_dev(i2sdev->control, i2sdev); - mutex_destroy(&i2sdev->lock); - kfree(i2sdev); -} - -static irqreturn_t i2sbus_bus_intr(int irq, void *devid) -{ - struct i2sbus_dev *dev = devid; - u32 intreg; - - spin_lock(&dev->low_lock); - intreg = in_le32(&dev->intfregs->intr_ctl); - - /* acknowledge interrupt reasons */ - out_le32(&dev->intfregs->intr_ctl, intreg); - - spin_unlock(&dev->low_lock); - - return IRQ_HANDLED; -} - - -/* - * XXX FIXME: We test the layout_id's here to get the proper way of - * mapping in various registers, thanks to bugs in Apple device-trees. - * We could instead key off the machine model and the name of the i2s - * node (i2s-a). This we'll do when we move it all to macio_asic.c - * and have that export items for each sub-node too. - */ -static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index, - int layout, struct resource *res) -{ - struct device_node *parent; - int pindex, rc = -ENXIO; - const u32 *reg; - - /* Machines with layout 76 and 36 (K2 based) have a weird device - * tree what we need to special case. - * Normal machines just fetch the resource from the i2s-X node. - * Darwin further divides normal machines into old and new layouts - * with a subtely different code path but that doesn't seem necessary - * in practice, they just bloated it. In addition, even on our K2 - * case the i2s-modem node, if we ever want to handle it, uses the - * normal layout - */ - if (layout != 76 && layout != 36) - return of_address_to_resource(np, index, res); - - parent = of_get_parent(np); - pindex = (index == aoa_resource_i2smmio) ? 0 : 1; - rc = of_address_to_resource(parent, pindex, res); - if (rc) - goto bail; - reg = of_get_property(np, "reg", NULL); - if (reg == NULL) { - rc = -ENXIO; - goto bail; - } - res->start += reg[index * 2]; - res->end = res->start + reg[index * 2 + 1] - 1; - bail: - of_node_put(parent); - return rc; -} - -/* FIXME: look at device node refcounting */ -static int i2sbus_add_dev(struct macio_dev *macio, - struct i2sbus_control *control, - struct device_node *np) -{ - struct i2sbus_dev *dev; - struct device_node *child = NULL, *sound = NULL; - struct resource *r; - int i, layout = 0, rlen, ok = force; - static const char *rnames[] = { "i2sbus: %s (control)", - "i2sbus: %s (tx)", - "i2sbus: %s (rx)" }; - static irq_handler_t ints[] = { - i2sbus_bus_intr, - i2sbus_tx_intr, - i2sbus_rx_intr - }; - - if (strlen(np->name) != 5) - return 0; - if (strncmp(np->name, "i2s-", 4)) - return 0; - - dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); - if (!dev) - return 0; - - i = 0; - while ((child = of_get_next_child(np, child))) { - if (strcmp(child->name, "sound") == 0) { - i++; - sound = child; - } - } - if (i == 1) { - const u32 *id = of_get_property(sound, "layout-id", NULL); - - if (id) { - layout = *id; - snprintf(dev->sound.modalias, 32, - "sound-layout-%d", layout); - ok = 1; - } else { - id = of_get_property(sound, "device-id", NULL); - /* - * We probably cannot handle all device-id machines, - * so restrict to those we do handle for now. - */ - if (id && (*id == 22 || *id == 14 || *id == 35)) { - snprintf(dev->sound.modalias, 32, - "aoa-device-id-%d", *id); - ok = 1; - layout = -1; - } - } - } - /* for the time being, until we can handle non-layout-id - * things in some fabric, refuse to attach if there is no - * layout-id property or we haven't been forced to attach. - * When there are two i2s busses and only one has a layout-id, - * then this depends on the order, but that isn't important - * either as the second one in that case is just a modem. */ - if (!ok) { - kfree(dev); - return -ENODEV; - } - - mutex_init(&dev->lock); - spin_lock_init(&dev->low_lock); - dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask; - dev->sound.ofdev.dev.of_node = np; - dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask; - dev->sound.ofdev.dev.parent = &macio->ofdev.dev; - dev->sound.ofdev.dev.release = i2sbus_release_dev; - dev->sound.attach_codec = i2sbus_attach_codec; - dev->sound.detach_codec = i2sbus_detach_codec; - dev->sound.pcmid = -1; - dev->macio = macio; - dev->control = control; - dev->bus_number = np->name[4] - 'a'; - INIT_LIST_HEAD(&dev->sound.codec_list); - - for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { - dev->interrupts[i] = -1; - snprintf(dev->rnames[i], sizeof(dev->rnames[i]), - rnames[i], np->name); - } - for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { - int irq = irq_of_parse_and_map(np, i); - if (request_irq(irq, ints[i], 0, dev->rnames[i], dev)) - goto err; - dev->interrupts[i] = irq; - } - - - /* Resource handling is problematic as some device-trees contain - * useless crap (ugh ugh ugh). We work around that here by calling - * specific functions for calculating the appropriate resources. - * - * This will all be moved to macio_asic.c at one point - */ - for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { - if (i2sbus_get_and_fixup_rsrc(np,i,layout,&dev->resources[i])) - goto err; - /* If only we could use our resource dev->resources[i]... - * but request_resource doesn't know about parents and - * contained resources... - */ - dev->allocated_resource[i] = - request_mem_region(dev->resources[i].start, - resource_size(&dev->resources[i]), - dev->rnames[i]); - if (!dev->allocated_resource[i]) { - printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i); - goto err; - } - } - - r = &dev->resources[aoa_resource_i2smmio]; - rlen = resource_size(r); - if (rlen < sizeof(struct i2s_interface_regs)) - goto err; - dev->intfregs = ioremap(r->start, rlen); - - r = &dev->resources[aoa_resource_txdbdma]; - rlen = resource_size(r); - if (rlen < sizeof(struct dbdma_regs)) - goto err; - dev->out.dbdma = ioremap(r->start, rlen); - - r = &dev->resources[aoa_resource_rxdbdma]; - rlen = resource_size(r); - if (rlen < sizeof(struct dbdma_regs)) - goto err; - dev->in.dbdma = ioremap(r->start, rlen); - - if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma) - goto err; - - if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring, - MAX_DBDMA_COMMANDS)) - goto err; - if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring, - MAX_DBDMA_COMMANDS)) - goto err; - - if (i2sbus_control_add_dev(dev->control, dev)) { - printk(KERN_ERR "i2sbus: control layer didn't like bus\n"); - goto err; - } - - if (soundbus_add_one(&dev->sound)) { - printk(KERN_DEBUG "i2sbus: device registration error!\n"); - goto err; - } - - /* enable this cell */ - i2sbus_control_cell(dev->control, dev, 1); - i2sbus_control_enable(dev->control, dev); - i2sbus_control_clock(dev->control, dev, 1); - - return 1; - err: - for (i=0;i<3;i++) - if (dev->interrupts[i] != -1) - free_irq(dev->interrupts[i], dev); - free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring); - free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring); - if (dev->intfregs) iounmap(dev->intfregs); - if (dev->out.dbdma) iounmap(dev->out.dbdma); - if (dev->in.dbdma) iounmap(dev->in.dbdma); - for (i=0;i<3;i++) - if (dev->allocated_resource[i]) - release_and_free_resource(dev->allocated_resource[i]); - mutex_destroy(&dev->lock); - kfree(dev); - return 0; -} - -static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) -{ - struct device_node *np = NULL; - int got = 0, err; - struct i2sbus_control *control = NULL; - - err = i2sbus_control_init(dev, &control); - if (err) - return err; - if (!control) { - printk(KERN_ERR "i2sbus_control_init API breakage\n"); - return -ENODEV; - } - - while ((np = of_get_next_child(dev->ofdev.dev.of_node, np))) { - if (of_device_is_compatible(np, "i2sbus") || - of_device_is_compatible(np, "i2s-modem")) { - got += i2sbus_add_dev(dev, control, np); - } - } - - if (!got) { - /* found none, clean up */ - i2sbus_control_destroy(control); - return -ENODEV; - } - - dev_set_drvdata(&dev->ofdev.dev, control); - - return 0; -} - -static int i2sbus_remove(struct macio_dev* dev) -{ - struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); - struct i2sbus_dev *i2sdev, *tmp; - - list_for_each_entry_safe(i2sdev, tmp, &control->list, item) - soundbus_remove_one(&i2sdev->sound); - - return 0; -} - -#ifdef CONFIG_PM -static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) -{ - struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); - struct codec_info_item *cii; - struct i2sbus_dev* i2sdev; - int err, ret = 0; - - list_for_each_entry(i2sdev, &control->list, item) { - /* Notify Alsa */ - if (i2sdev->sound.pcm) { - /* Suspend PCM streams */ - snd_pcm_suspend_all(i2sdev->sound.pcm); - } - - /* Notify codecs */ - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { - err = 0; - if (cii->codec->suspend) - err = cii->codec->suspend(cii, state); - if (err) - ret = err; - } - - /* wait until streams are stopped */ - i2sbus_wait_for_stop_both(i2sdev); - } - - return ret; -} - -static int i2sbus_resume(struct macio_dev* dev) -{ - struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); - struct codec_info_item *cii; - struct i2sbus_dev* i2sdev; - int err, ret = 0; - - list_for_each_entry(i2sdev, &control->list, item) { - /* reset i2s bus format etc. */ - i2sbus_pcm_prepare_both(i2sdev); - - /* Notify codecs so they can re-initialize */ - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { - err = 0; - if (cii->codec->resume) - err = cii->codec->resume(cii); - if (err) - ret = err; - } - } - - return ret; -} -#endif /* CONFIG_PM */ - -static int i2sbus_shutdown(struct macio_dev* dev) -{ - return 0; -} - -static struct macio_driver i2sbus_drv = { - .driver = { - .name = "soundbus-i2s", - .owner = THIS_MODULE, - .of_match_table = i2sbus_match, - }, - .probe = i2sbus_probe, - .remove = i2sbus_remove, -#ifdef CONFIG_PM - .suspend = i2sbus_suspend, - .resume = i2sbus_resume, -#endif - .shutdown = i2sbus_shutdown, -}; - -static int __init soundbus_i2sbus_init(void) -{ - return macio_register_driver(&i2sbus_drv); -} - -static void __exit soundbus_i2sbus_exit(void) -{ - macio_unregister_driver(&i2sbus_drv); -} - -module_init(soundbus_i2sbus_init); -module_exit(soundbus_i2sbus_exit); diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h deleted file mode 100644 index befefd99..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * i2sbus driver -- private definitions - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ -#ifndef __I2SBUS_H -#define __I2SBUS_H -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/completion.h> - -#include <sound/pcm.h> - -#include <asm/prom.h> -#include <asm/pmac_feature.h> -#include <asm/dbdma.h> - -#include "interface.h" -#include "../soundbus.h" - -struct i2sbus_control { - struct list_head list; - struct macio_chip *macio; -}; - -#define MAX_DBDMA_COMMANDS 32 - -struct dbdma_command_mem { - dma_addr_t bus_addr; - dma_addr_t bus_cmd_start; - struct dbdma_cmd *cmds; - void *space; - int size; - u32 running:1; - u32 stopping:1; -}; - -struct pcm_info { - u32 created:1, /* has this direction been created with alsa? */ - active:1; /* is this stream active? */ - /* runtime information */ - struct snd_pcm_substream *substream; - int current_period; - u32 frame_count; - struct dbdma_command_mem dbdma_ring; - volatile struct dbdma_regs __iomem *dbdma; - struct completion *stop_completion; -}; - -enum { - aoa_resource_i2smmio = 0, - aoa_resource_txdbdma, - aoa_resource_rxdbdma, -}; - -struct i2sbus_dev { - struct soundbus_dev sound; - struct macio_dev *macio; - struct i2sbus_control *control; - volatile struct i2s_interface_regs __iomem *intfregs; - - struct resource resources[3]; - struct resource *allocated_resource[3]; - int interrupts[3]; - char rnames[3][32]; - - /* info about currently active substreams */ - struct pcm_info out, in; - snd_pcm_format_t format; - unsigned int rate; - - /* list for a single controller */ - struct list_head item; - /* number of bus on controller */ - int bus_number; - /* for use by control layer */ - struct pmf_function *enable, - *cell_enable, - *cell_disable, - *clock_enable, - *clock_disable; - - /* locks */ - /* spinlock for low-level interrupt locking */ - spinlock_t low_lock; - /* mutex for high-level consistency */ - struct mutex lock; -}; - -#define soundbus_dev_to_i2sbus_dev(sdev) \ - container_of(sdev, struct i2sbus_dev, sound) - -/* pcm specific functions */ -extern int -i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, - struct codec_info *ci, void *data); -extern void -i2sbus_detach_codec(struct soundbus_dev *dev, void *data); -extern irqreturn_t -i2sbus_tx_intr(int irq, void *devid); -extern irqreturn_t -i2sbus_rx_intr(int irq, void *devid); - -extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev); -extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev); - -/* control specific functions */ -extern int i2sbus_control_init(struct macio_dev* dev, - struct i2sbus_control **c); -extern void i2sbus_control_destroy(struct i2sbus_control *c); -extern int i2sbus_control_add_dev(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev); -extern void i2sbus_control_remove_dev(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev); -extern int i2sbus_control_enable(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev); -extern int i2sbus_control_cell(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev, - int enable); -extern int i2sbus_control_clock(struct i2sbus_control *c, - struct i2sbus_dev *i2sdev, - int enable); -#endif /* __I2SBUS_H */ diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h deleted file mode 100644 index c6b5f545..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * i2sbus driver -- interface register definitions - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ -#ifndef __I2SBUS_INTERFACE_H -#define __I2SBUS_INTERFACE_H - -/* i2s bus control registers, at least what we know about them */ - -#define __PAD(m,n) u8 __pad##m[n] -#define _PAD(line, n) __PAD(line, n) -#define PAD(n) _PAD(__LINE__, (n)) -struct i2s_interface_regs { - __le32 intr_ctl; /* 0x00 */ - PAD(12); - __le32 serial_format; /* 0x10 */ - PAD(12); - __le32 codec_msg_out; /* 0x20 */ - PAD(12); - __le32 codec_msg_in; /* 0x30 */ - PAD(12); - __le32 frame_count; /* 0x40 */ - PAD(12); - __le32 frame_match; /* 0x50 */ - PAD(12); - __le32 data_word_sizes; /* 0x60 */ - PAD(12); - __le32 peak_level_sel; /* 0x70 */ - PAD(12); - __le32 peak_level_in0; /* 0x80 */ - PAD(12); - __le32 peak_level_in1; /* 0x90 */ - PAD(12); - /* total size: 0x100 bytes */ -} __attribute__((__packed__)); - -/* interrupt register is just a bitfield with - * interrupt enable and pending bits */ -#define I2S_REG_INTR_CTL 0x00 -# define I2S_INT_FRAME_COUNT (1<<31) -# define I2S_PENDING_FRAME_COUNT (1<<30) -# define I2S_INT_MESSAGE_FLAG (1<<29) -# define I2S_PENDING_MESSAGE_FLAG (1<<28) -# define I2S_INT_NEW_PEAK (1<<27) -# define I2S_PENDING_NEW_PEAK (1<<26) -# define I2S_INT_CLOCKS_STOPPED (1<<25) -# define I2S_PENDING_CLOCKS_STOPPED (1<<24) -# define I2S_INT_EXTERNAL_SYNC_ERROR (1<<23) -# define I2S_PENDING_EXTERNAL_SYNC_ERROR (1<<22) -# define I2S_INT_EXTERNAL_SYNC_OK (1<<21) -# define I2S_PENDING_EXTERNAL_SYNC_OK (1<<20) -# define I2S_INT_NEW_SAMPLE_RATE (1<<19) -# define I2S_PENDING_NEW_SAMPLE_RATE (1<<18) -# define I2S_INT_STATUS_FLAG (1<<17) -# define I2S_PENDING_STATUS_FLAG (1<<16) - -/* serial format register is more interesting :) - * It contains: - * - clock source - * - MClk divisor - * - SClk divisor - * - SClk master flag - * - serial format (sony, i2s 64x, i2s 32x, dav, silabs) - * - external sample frequency interrupt (don't understand) - * - external sample frequency - */ -#define I2S_REG_SERIAL_FORMAT 0x10 -/* clock source. You get either 18.432, 45.1584 or 49.1520 MHz */ -# define I2S_SF_CLOCK_SOURCE_SHIFT 30 -# define I2S_SF_CLOCK_SOURCE_MASK (3<<I2S_SF_CLOCK_SOURCE_SHIFT) -# define I2S_SF_CLOCK_SOURCE_18MHz (0<<I2S_SF_CLOCK_SOURCE_SHIFT) -# define I2S_SF_CLOCK_SOURCE_45MHz (1<<I2S_SF_CLOCK_SOURCE_SHIFT) -# define I2S_SF_CLOCK_SOURCE_49MHz (2<<I2S_SF_CLOCK_SOURCE_SHIFT) -/* also, let's define the exact clock speeds here, in Hz */ -#define I2S_CLOCK_SPEED_18MHz 18432000 -#define I2S_CLOCK_SPEED_45MHz 45158400 -#define I2S_CLOCK_SPEED_49MHz 49152000 -/* MClk is the clock that drives the codec, usually called its 'system clock'. - * It is derived by taking only every 'divisor' tick of the clock. - */ -# define I2S_SF_MCLKDIV_SHIFT 24 -# define I2S_SF_MCLKDIV_MASK (0x1F<<I2S_SF_MCLKDIV_SHIFT) -# define I2S_SF_MCLKDIV_1 (0x14<<I2S_SF_MCLKDIV_SHIFT) -# define I2S_SF_MCLKDIV_3 (0x13<<I2S_SF_MCLKDIV_SHIFT) -# define I2S_SF_MCLKDIV_5 (0x12<<I2S_SF_MCLKDIV_SHIFT) -# define I2S_SF_MCLKDIV_14 (0x0E<<I2S_SF_MCLKDIV_SHIFT) -# define I2S_SF_MCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_MCLKDIV_SHIFT)&I2S_SF_MCLKDIV_MASK) -static inline int i2s_sf_mclkdiv(int div, int *out) -{ - int d; - - switch(div) { - case 1: *out |= I2S_SF_MCLKDIV_1; return 0; - case 3: *out |= I2S_SF_MCLKDIV_3; return 0; - case 5: *out |= I2S_SF_MCLKDIV_5; return 0; - case 14: *out |= I2S_SF_MCLKDIV_14; return 0; - default: - if (div%2) return -1; - d = div/2-1; - if (d == 0x14 || d == 0x13 || d == 0x12 || d == 0x0E) - return -1; - *out |= I2S_SF_MCLKDIV_OTHER(div); - return 0; - } -} -/* SClk is the clock that drives the i2s wire bus. Note that it is - * derived from the MClk above by taking only every 'divisor' tick - * of MClk. - */ -# define I2S_SF_SCLKDIV_SHIFT 20 -# define I2S_SF_SCLKDIV_MASK (0xF<<I2S_SF_SCLKDIV_SHIFT) -# define I2S_SF_SCLKDIV_1 (8<<I2S_SF_SCLKDIV_SHIFT) -# define I2S_SF_SCLKDIV_3 (9<<I2S_SF_SCLKDIV_SHIFT) -# define I2S_SF_SCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_SCLKDIV_SHIFT)&I2S_SF_SCLKDIV_MASK) -static inline int i2s_sf_sclkdiv(int div, int *out) -{ - int d; - - switch(div) { - case 1: *out |= I2S_SF_SCLKDIV_1; return 0; - case 3: *out |= I2S_SF_SCLKDIV_3; return 0; - default: - if (div%2) return -1; - d = div/2-1; - if (d == 8 || d == 9) return -1; - *out |= I2S_SF_SCLKDIV_OTHER(div); - return 0; - } -} -# define I2S_SF_SCLK_MASTER (1<<19) -/* serial format is the way the data is put to the i2s wire bus */ -# define I2S_SF_SERIAL_FORMAT_SHIFT 16 -# define I2S_SF_SERIAL_FORMAT_MASK (7<<I2S_SF_SERIAL_FORMAT_SHIFT) -# define I2S_SF_SERIAL_FORMAT_SONY (0<<I2S_SF_SERIAL_FORMAT_SHIFT) -# define I2S_SF_SERIAL_FORMAT_I2S_64X (1<<I2S_SF_SERIAL_FORMAT_SHIFT) -# define I2S_SF_SERIAL_FORMAT_I2S_32X (2<<I2S_SF_SERIAL_FORMAT_SHIFT) -# define I2S_SF_SERIAL_FORMAT_I2S_DAV (4<<I2S_SF_SERIAL_FORMAT_SHIFT) -# define I2S_SF_SERIAL_FORMAT_I2S_SILABS (5<<I2S_SF_SERIAL_FORMAT_SHIFT) -/* unknown */ -# define I2S_SF_EXT_SAMPLE_FREQ_INT_SHIFT 12 -# define I2S_SF_EXT_SAMPLE_FREQ_INT_MASK (0xF<<I2S_SF_SAMPLE_FREQ_INT_SHIFT) -/* probably gives external frequency? */ -# define I2S_SF_EXT_SAMPLE_FREQ_MASK 0xFFF - -/* used to send codec messages, but how isn't clear */ -#define I2S_REG_CODEC_MSG_OUT 0x20 - -/* used to receive codec messages, but how isn't clear */ -#define I2S_REG_CODEC_MSG_IN 0x30 - -/* frame count reg isn't clear to me yet, but probably useful */ -#define I2S_REG_FRAME_COUNT 0x40 - -/* program to some value, and get interrupt if frame count reaches it */ -#define I2S_REG_FRAME_MATCH 0x50 - -/* this register describes how the bus transfers data */ -#define I2S_REG_DATA_WORD_SIZES 0x60 -/* number of interleaved input channels */ -# define I2S_DWS_NUM_CHANNELS_IN_SHIFT 24 -# define I2S_DWS_NUM_CHANNELS_IN_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_IN_SHIFT) -/* word size of input data */ -# define I2S_DWS_DATA_IN_SIZE_SHIFT 16 -# define I2S_DWS_DATA_IN_16BIT (0<<I2S_DWS_DATA_IN_SIZE_SHIFT) -# define I2S_DWS_DATA_IN_24BIT (3<<I2S_DWS_DATA_IN_SIZE_SHIFT) -/* number of interleaved output channels */ -# define I2S_DWS_NUM_CHANNELS_OUT_SHIFT 8 -# define I2S_DWS_NUM_CHANNELS_OUT_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_OUT_SHIFT) -/* word size of output data */ -# define I2S_DWS_DATA_OUT_SIZE_SHIFT 0 -# define I2S_DWS_DATA_OUT_16BIT (0<<I2S_DWS_DATA_OUT_SIZE_SHIFT) -# define I2S_DWS_DATA_OUT_24BIT (3<<I2S_DWS_DATA_OUT_SIZE_SHIFT) - - -/* unknown */ -#define I2S_REG_PEAK_LEVEL_SEL 0x70 - -/* unknown */ -#define I2S_REG_PEAK_LEVEL_IN0 0x80 - -/* unknown */ -#define I2S_REG_PEAK_LEVEL_IN1 0x90 - -#endif /* __I2SBUS_INTERFACE_H */ diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c deleted file mode 100644 index 19491ed9..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * i2sbus driver -- pcm routines - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ - -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <sound/core.h> -#include <asm/macio.h> -#include <linux/pci.h> -#include <linux/module.h> -#include "../soundbus.h" -#include "i2sbus.h" - -static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in, - struct pcm_info **pi, struct pcm_info **other) -{ - if (in) { - if (pi) - *pi = &i2sdev->in; - if (other) - *other = &i2sdev->out; - } else { - if (pi) - *pi = &i2sdev->out; - if (other) - *other = &i2sdev->in; - } -} - -static int clock_and_divisors(int mclk, int sclk, int rate, int *out) -{ - /* sclk must be derived from mclk! */ - if (mclk % sclk) - return -1; - /* derive sclk register value */ - if (i2s_sf_sclkdiv(mclk / sclk, out)) - return -1; - - if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) { - if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) { - *out |= I2S_SF_CLOCK_SOURCE_18MHz; - return 0; - } - } - if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) { - if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) { - *out |= I2S_SF_CLOCK_SOURCE_45MHz; - return 0; - } - } - if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) { - if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) { - *out |= I2S_SF_CLOCK_SOURCE_49MHz; - return 0; - } - } - return -1; -} - -#define CHECK_RATE(rate) \ - do { if (rates & SNDRV_PCM_RATE_ ##rate) { \ - int dummy; \ - if (clock_and_divisors(sysclock_factor, \ - bus_factor, rate, &dummy)) \ - rates &= ~SNDRV_PCM_RATE_ ##rate; \ - } } while (0) - -static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) -{ - struct pcm_info *pi, *other; - struct soundbus_dev *sdev; - int masks_inited = 0, err; - struct codec_info_item *cii, *rev; - struct snd_pcm_hardware *hw; - u64 formats = 0; - unsigned int rates = 0; - struct transfer_info v; - int result = 0; - int bus_factor = 0, sysclock_factor = 0; - int found_this; - - mutex_lock(&i2sdev->lock); - - get_pcm_info(i2sdev, in, &pi, &other); - - hw = &pi->substream->runtime->hw; - sdev = &i2sdev->sound; - - if (pi->active) { - /* alsa messed up */ - result = -EBUSY; - goto out_unlock; - } - - /* we now need to assign the hw */ - list_for_each_entry(cii, &sdev->codec_list, list) { - struct transfer_info *ti = cii->codec->transfers; - bus_factor = cii->codec->bus_factor; - sysclock_factor = cii->codec->sysclock_factor; - while (ti->formats && ti->rates) { - v = *ti; - if (ti->transfer_in == in - && cii->codec->usable(cii, ti, &v)) { - if (masks_inited) { - formats &= v.formats; - rates &= v.rates; - } else { - formats = v.formats; - rates = v.rates; - masks_inited = 1; - } - } - ti++; - } - } - if (!masks_inited || !bus_factor || !sysclock_factor) { - result = -ENODEV; - goto out_unlock; - } - /* bus dependent stuff */ - hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_JOINT_DUPLEX; - - CHECK_RATE(5512); - CHECK_RATE(8000); - CHECK_RATE(11025); - CHECK_RATE(16000); - CHECK_RATE(22050); - CHECK_RATE(32000); - CHECK_RATE(44100); - CHECK_RATE(48000); - CHECK_RATE(64000); - CHECK_RATE(88200); - CHECK_RATE(96000); - CHECK_RATE(176400); - CHECK_RATE(192000); - hw->rates = rates; - - /* well. the codec might want 24 bits only, and we'll - * ever only transfer 24 bits, but they are top-aligned! - * So for alsa, we claim that we're doing full 32 bit - * while in reality we'll ignore the lower 8 bits of - * that when doing playback (they're transferred as 0 - * as far as I know, no codecs we have are 32-bit capable - * so I can't really test) and when doing recording we'll - * always have those lower 8 bits recorded as 0 */ - if (formats & SNDRV_PCM_FMTBIT_S24_BE) - formats |= SNDRV_PCM_FMTBIT_S32_BE; - if (formats & SNDRV_PCM_FMTBIT_U24_BE) - formats |= SNDRV_PCM_FMTBIT_U32_BE; - /* now mask off what we can support. I suppose we could - * also support S24_3LE and some similar formats, but I - * doubt there's a codec that would be able to use that, - * so we don't support it here. */ - hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_U16_BE | - SNDRV_PCM_FMTBIT_S32_BE | - SNDRV_PCM_FMTBIT_U32_BE); - - /* we need to set the highest and lowest rate possible. - * These are the highest and lowest rates alsa can - * support properly in its bitfield. - * Below, we'll use that to restrict to the rate - * currently in use (if any). */ - hw->rate_min = 5512; - hw->rate_max = 192000; - /* if the other stream is active, then we can only - * support what it is currently using. - * FIXME: I lied. This comment is wrong. We can support - * anything that works with the same serial format, ie. - * when recording 24 bit sound we can well play 16 bit - * sound at the same time iff using the same transfer mode. - */ - if (other->active) { - /* FIXME: is this guaranteed by the alsa api? */ - hw->formats &= (1ULL << i2sdev->format); - /* see above, restrict rates to the one we already have */ - hw->rate_min = i2sdev->rate; - hw->rate_max = i2sdev->rate; - } - - hw->channels_min = 2; - hw->channels_max = 2; - /* these are somewhat arbitrary */ - hw->buffer_bytes_max = 131072; - hw->period_bytes_min = 256; - hw->period_bytes_max = 16384; - hw->periods_min = 3; - hw->periods_max = MAX_DBDMA_COMMANDS; - err = snd_pcm_hw_constraint_integer(pi->substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - result = err; - goto out_unlock; - } - list_for_each_entry(cii, &sdev->codec_list, list) { - if (cii->codec->open) { - err = cii->codec->open(cii, pi->substream); - if (err) { - result = err; - /* unwind */ - found_this = 0; - list_for_each_entry_reverse(rev, - &sdev->codec_list, list) { - if (found_this && rev->codec->close) { - rev->codec->close(rev, - pi->substream); - } - if (rev == cii) - found_this = 1; - } - goto out_unlock; - } - } - } - - out_unlock: - mutex_unlock(&i2sdev->lock); - return result; -} - -#undef CHECK_RATE - -static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) -{ - struct codec_info_item *cii; - struct pcm_info *pi; - int err = 0, tmp; - - mutex_lock(&i2sdev->lock); - - get_pcm_info(i2sdev, in, &pi, NULL); - - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { - if (cii->codec->close) { - tmp = cii->codec->close(cii, pi->substream); - if (tmp) - err = tmp; - } - } - - pi->substream = NULL; - pi->active = 0; - mutex_unlock(&i2sdev->lock); - return err; -} - -static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev, - struct pcm_info *pi) -{ - unsigned long flags; - struct completion done; - long timeout; - - spin_lock_irqsave(&i2sdev->low_lock, flags); - if (pi->dbdma_ring.stopping) { - init_completion(&done); - pi->stop_completion = &done; - spin_unlock_irqrestore(&i2sdev->low_lock, flags); - timeout = wait_for_completion_timeout(&done, HZ); - spin_lock_irqsave(&i2sdev->low_lock, flags); - pi->stop_completion = NULL; - if (timeout == 0) { - /* timeout expired, stop dbdma forcefully */ - printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n"); - /* make sure RUN, PAUSE and S0 bits are cleared */ - out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); - pi->dbdma_ring.stopping = 0; - timeout = 10; - while (in_le32(&pi->dbdma->status) & ACTIVE) { - if (--timeout <= 0) - break; - udelay(1); - } - } - } - spin_unlock_irqrestore(&i2sdev->low_lock, flags); -} - -#ifdef CONFIG_PM -void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev) -{ - struct pcm_info *pi; - - get_pcm_info(i2sdev, 0, &pi, NULL); - i2sbus_wait_for_stop(i2sdev, pi); - get_pcm_info(i2sdev, 1, &pi, NULL); - i2sbus_wait_for_stop(i2sdev, pi); -} -#endif - -static int i2sbus_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); -} - -static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - struct pcm_info *pi; - - get_pcm_info(i2sdev, in, &pi, NULL); - if (pi->dbdma_ring.stopping) - i2sbus_wait_for_stop(i2sdev, pi); - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream) -{ - return i2sbus_hw_free(substream, 0); -} - -static int i2sbus_record_hw_free(struct snd_pcm_substream *substream) -{ - return i2sbus_hw_free(substream, 1); -} - -static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) -{ - /* whee. Hard work now. The user has selected a bitrate - * and bit format, so now we have to program our - * I2S controller appropriately. */ - struct snd_pcm_runtime *runtime; - struct dbdma_cmd *command; - int i, periodsize, nperiods; - dma_addr_t offset; - struct bus_info bi; - struct codec_info_item *cii; - int sfr = 0; /* serial format register */ - int dws = 0; /* data word sizes reg */ - int input_16bit; - struct pcm_info *pi, *other; - int cnt; - int result = 0; - unsigned int cmd, stopaddr; - - mutex_lock(&i2sdev->lock); - - get_pcm_info(i2sdev, in, &pi, &other); - - if (pi->dbdma_ring.running) { - result = -EBUSY; - goto out_unlock; - } - if (pi->dbdma_ring.stopping) - i2sbus_wait_for_stop(i2sdev, pi); - - if (!pi->substream || !pi->substream->runtime) { - result = -EINVAL; - goto out_unlock; - } - - runtime = pi->substream->runtime; - pi->active = 1; - if (other->active && - ((i2sdev->format != runtime->format) - || (i2sdev->rate != runtime->rate))) { - result = -EINVAL; - goto out_unlock; - } - - i2sdev->format = runtime->format; - i2sdev->rate = runtime->rate; - - periodsize = snd_pcm_lib_period_bytes(pi->substream); - nperiods = pi->substream->runtime->periods; - pi->current_period = 0; - - /* generate dbdma command ring first */ - command = pi->dbdma_ring.cmds; - memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd)); - - /* commands to DMA to/from the ring */ - /* - * For input, we need to do a graceful stop; if we abort - * the DMA, we end up with leftover bytes that corrupt - * the next recording. To do this we set the S0 status - * bit and wait for the DMA controller to stop. Each - * command has a branch condition to - * make it branch to a stop command if S0 is set. - * On input we also need to wait for the S7 bit to be - * set before turning off the DMA controller. - * In fact we do the graceful stop for output as well. - */ - offset = runtime->dma_addr; - cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS; - stopaddr = pi->dbdma_ring.bus_cmd_start + - (nperiods + 1) * sizeof(struct dbdma_cmd); - for (i = 0; i < nperiods; i++, command++, offset += periodsize) { - command->command = cpu_to_le16(cmd); - command->cmd_dep = cpu_to_le32(stopaddr); - command->phy_addr = cpu_to_le32(offset); - command->req_count = cpu_to_le16(periodsize); - } - - /* branch back to beginning of ring */ - command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); - command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); - command++; - - /* set stop command */ - command->command = cpu_to_le16(DBDMA_STOP); - - /* ok, let's set the serial format and stuff */ - switch (runtime->format) { - /* 16 bit formats */ - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_U16_BE: - /* FIXME: if we add different bus factors we need to - * do more here!! */ - bi.bus_factor = 0; - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { - bi.bus_factor = cii->codec->bus_factor; - break; - } - if (!bi.bus_factor) { - result = -ENODEV; - goto out_unlock; - } - input_16bit = 1; - break; - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_U32_BE: - /* force 64x bus speed, otherwise the data cannot be - * transferred quickly enough! */ - bi.bus_factor = 64; - input_16bit = 0; - break; - default: - result = -EINVAL; - goto out_unlock; - } - /* we assume all sysclocks are the same! */ - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { - bi.sysclock_factor = cii->codec->sysclock_factor; - break; - } - - if (clock_and_divisors(bi.sysclock_factor, - bi.bus_factor, - runtime->rate, - &sfr) < 0) { - result = -EINVAL; - goto out_unlock; - } - switch (bi.bus_factor) { - case 32: - sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X; - break; - case 64: - sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X; - break; - } - /* FIXME: THIS ASSUMES MASTER ALL THE TIME */ - sfr |= I2S_SF_SCLK_MASTER; - - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { - int err = 0; - if (cii->codec->prepare) - err = cii->codec->prepare(cii, &bi, pi->substream); - if (err) { - result = err; - goto out_unlock; - } - } - /* codecs are fine with it, so set our clocks */ - if (input_16bit) - dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | - (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | - I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT; - else - dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | - (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | - I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT; - - /* early exit if already programmed correctly */ - /* not locking these is fine since we touch them only in this function */ - if (in_le32(&i2sdev->intfregs->serial_format) == sfr - && in_le32(&i2sdev->intfregs->data_word_sizes) == dws) - goto out_unlock; - - /* let's notify the codecs about clocks going away. - * For now we only do mastering on the i2s cell... */ - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) - if (cii->codec->switch_clock) - cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE); - - i2sbus_control_enable(i2sdev->control, i2sdev); - i2sbus_control_cell(i2sdev->control, i2sdev, 1); - - out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); - - i2sbus_control_clock(i2sdev->control, i2sdev, 0); - - msleep(1); - - /* wait for clock stopped. This can apparently take a while... */ - cnt = 100; - while (cnt-- && - !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) { - msleep(5); - } - out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); - - /* not locking these is fine since we touch them only in this function */ - out_le32(&i2sdev->intfregs->serial_format, sfr); - out_le32(&i2sdev->intfregs->data_word_sizes, dws); - - i2sbus_control_enable(i2sdev->control, i2sdev); - i2sbus_control_cell(i2sdev->control, i2sdev, 1); - i2sbus_control_clock(i2sdev->control, i2sdev, 1); - msleep(1); - - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) - if (cii->codec->switch_clock) - cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE); - - out_unlock: - mutex_unlock(&i2sdev->lock); - return result; -} - -#ifdef CONFIG_PM -void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev) -{ - i2sbus_pcm_prepare(i2sdev, 0); - i2sbus_pcm_prepare(i2sdev, 1); -} -#endif - -static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) -{ - struct codec_info_item *cii; - struct pcm_info *pi; - int result = 0; - unsigned long flags; - - spin_lock_irqsave(&i2sdev->low_lock, flags); - - get_pcm_info(i2sdev, in, &pi, NULL); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - if (pi->dbdma_ring.running) { - result = -EALREADY; - goto out_unlock; - } - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) - if (cii->codec->start) - cii->codec->start(cii, pi->substream); - pi->dbdma_ring.running = 1; - - if (pi->dbdma_ring.stopping) { - /* Clear the S0 bit, then see if we stopped yet */ - out_le32(&pi->dbdma->control, 1 << 16); - if (in_le32(&pi->dbdma->status) & ACTIVE) { - /* possible race here? */ - udelay(10); - if (in_le32(&pi->dbdma->status) & ACTIVE) { - pi->dbdma_ring.stopping = 0; - goto out_unlock; /* keep running */ - } - } - } - - /* make sure RUN, PAUSE and S0 bits are cleared */ - out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); - - /* set branch condition select register */ - out_le32(&pi->dbdma->br_sel, (1 << 16) | 1); - - /* write dma command buffer address to the dbdma chip */ - out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); - - /* initialize the frame count and current period */ - pi->current_period = 0; - pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); - - /* set the DMA controller running */ - out_le32(&pi->dbdma->control, (RUN << 16) | RUN); - - /* off you go! */ - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - if (!pi->dbdma_ring.running) { - result = -EALREADY; - goto out_unlock; - } - pi->dbdma_ring.running = 0; - - /* Set the S0 bit to make the DMA branch to the stop cmd */ - out_le32(&pi->dbdma->control, (1 << 16) | 1); - pi->dbdma_ring.stopping = 1; - - list_for_each_entry(cii, &i2sdev->sound.codec_list, list) - if (cii->codec->stop) - cii->codec->stop(cii, pi->substream); - break; - default: - result = -EINVAL; - goto out_unlock; - } - - out_unlock: - spin_unlock_irqrestore(&i2sdev->low_lock, flags); - return result; -} - -static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) -{ - struct pcm_info *pi; - u32 fc; - - get_pcm_info(i2sdev, in, &pi, NULL); - - fc = in_le32(&i2sdev->intfregs->frame_count); - fc = fc - pi->frame_count; - - if (fc >= pi->substream->runtime->buffer_size) - fc %= pi->substream->runtime->buffer_size; - return fc; -} - -static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) -{ - struct pcm_info *pi; - u32 fc, nframes; - u32 status; - int timeout, i; - int dma_stopped = 0; - struct snd_pcm_runtime *runtime; - - spin_lock(&i2sdev->low_lock); - get_pcm_info(i2sdev, in, &pi, NULL); - if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) - goto out_unlock; - - i = pi->current_period; - runtime = pi->substream->runtime; - while (pi->dbdma_ring.cmds[i].xfer_status) { - if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) - /* - * BT is the branch taken bit. If it took a branch - * it is because we set the S0 bit to make it - * branch to the stop command. - */ - dma_stopped = 1; - pi->dbdma_ring.cmds[i].xfer_status = 0; - - if (++i >= runtime->periods) { - i = 0; - pi->frame_count += runtime->buffer_size; - } - pi->current_period = i; - - /* - * Check the frame count. The DMA tends to get a bit - * ahead of the frame counter, which confuses the core. - */ - fc = in_le32(&i2sdev->intfregs->frame_count); - nframes = i * runtime->period_size; - if (fc < pi->frame_count + nframes) - pi->frame_count = fc - nframes; - } - - if (dma_stopped) { - timeout = 1000; - for (;;) { - status = in_le32(&pi->dbdma->status); - if (!(status & ACTIVE) && (!in || (status & 0x80))) - break; - if (--timeout <= 0) { - printk(KERN_ERR "i2sbus: timed out " - "waiting for DMA to stop!\n"); - break; - } - udelay(1); - } - - /* Turn off DMA controller, clear S0 bit */ - out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); - - pi->dbdma_ring.stopping = 0; - if (pi->stop_completion) - complete(pi->stop_completion); - } - - if (!pi->dbdma_ring.running) - goto out_unlock; - spin_unlock(&i2sdev->low_lock); - /* may call _trigger again, hence needs to be unlocked */ - snd_pcm_period_elapsed(pi->substream); - return; - - out_unlock: - spin_unlock(&i2sdev->low_lock); -} - -irqreturn_t i2sbus_tx_intr(int irq, void *devid) -{ - handle_interrupt((struct i2sbus_dev *)devid, 0); - return IRQ_HANDLED; -} - -irqreturn_t i2sbus_rx_intr(int irq, void *devid) -{ - handle_interrupt((struct i2sbus_dev *)devid, 1); - return IRQ_HANDLED; -} - -static int i2sbus_playback_open(struct snd_pcm_substream *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - i2sdev->out.substream = substream; - return i2sbus_pcm_open(i2sdev, 0); -} - -static int i2sbus_playback_close(struct snd_pcm_substream *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - int err; - - if (!i2sdev) - return -EINVAL; - if (i2sdev->out.substream != substream) - return -EINVAL; - err = i2sbus_pcm_close(i2sdev, 0); - if (!err) - i2sdev->out.substream = NULL; - return err; -} - -static int i2sbus_playback_prepare(struct snd_pcm_substream *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - if (i2sdev->out.substream != substream) - return -EINVAL; - return i2sbus_pcm_prepare(i2sdev, 0); -} - -static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - if (i2sdev->out.substream != substream) - return -EINVAL; - return i2sbus_pcm_trigger(i2sdev, 0, cmd); -} - -static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream - *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - if (i2sdev->out.substream != substream) - return 0; - return i2sbus_pcm_pointer(i2sdev, 0); -} - -static struct snd_pcm_ops i2sbus_playback_ops = { - .open = i2sbus_playback_open, - .close = i2sbus_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = i2sbus_hw_params, - .hw_free = i2sbus_playback_hw_free, - .prepare = i2sbus_playback_prepare, - .trigger = i2sbus_playback_trigger, - .pointer = i2sbus_playback_pointer, -}; - -static int i2sbus_record_open(struct snd_pcm_substream *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - i2sdev->in.substream = substream; - return i2sbus_pcm_open(i2sdev, 1); -} - -static int i2sbus_record_close(struct snd_pcm_substream *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - int err; - - if (!i2sdev) - return -EINVAL; - if (i2sdev->in.substream != substream) - return -EINVAL; - err = i2sbus_pcm_close(i2sdev, 1); - if (!err) - i2sdev->in.substream = NULL; - return err; -} - -static int i2sbus_record_prepare(struct snd_pcm_substream *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - if (i2sdev->in.substream != substream) - return -EINVAL; - return i2sbus_pcm_prepare(i2sdev, 1); -} - -static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - if (i2sdev->in.substream != substream) - return -EINVAL; - return i2sbus_pcm_trigger(i2sdev, 1, cmd); -} - -static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream - *substream) -{ - struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); - - if (!i2sdev) - return -EINVAL; - if (i2sdev->in.substream != substream) - return 0; - return i2sbus_pcm_pointer(i2sdev, 1); -} - -static struct snd_pcm_ops i2sbus_record_ops = { - .open = i2sbus_record_open, - .close = i2sbus_record_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = i2sbus_hw_params, - .hw_free = i2sbus_record_hw_free, - .prepare = i2sbus_record_prepare, - .trigger = i2sbus_record_trigger, - .pointer = i2sbus_record_pointer, -}; - -static void i2sbus_private_free(struct snd_pcm *pcm) -{ - struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm); - struct codec_info_item *p, *tmp; - - i2sdev->sound.pcm = NULL; - i2sdev->out.created = 0; - i2sdev->in.created = 0; - list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) { - printk(KERN_ERR "i2sbus: a codec didn't unregister!\n"); - list_del(&p->list); - module_put(p->codec->owner); - kfree(p); - } - soundbus_dev_put(&i2sdev->sound); - module_put(THIS_MODULE); -} - -int -i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, - struct codec_info *ci, void *data) -{ - int err, in = 0, out = 0; - struct transfer_info *tmp; - struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev); - struct codec_info_item *cii; - - if (!dev->pcmname || dev->pcmid == -1) { - printk(KERN_ERR "i2sbus: pcm name and id must be set!\n"); - return -EINVAL; - } - - list_for_each_entry(cii, &dev->codec_list, list) { - if (cii->codec_data == data) - return -EALREADY; - } - - if (!ci->transfers || !ci->transfers->formats - || !ci->transfers->rates || !ci->usable) - return -EINVAL; - - /* we currently code the i2s transfer on the clock, and support only - * 32 and 64 */ - if (ci->bus_factor != 32 && ci->bus_factor != 64) - return -EINVAL; - - /* If you want to fix this, you need to keep track of what transport infos - * are to be used, which codecs they belong to, and then fix all the - * sysclock/busclock stuff above to depend on which is usable */ - list_for_each_entry(cii, &dev->codec_list, list) { - if (cii->codec->sysclock_factor != ci->sysclock_factor) { - printk(KERN_DEBUG - "cannot yet handle multiple different sysclocks!\n"); - return -EINVAL; - } - if (cii->codec->bus_factor != ci->bus_factor) { - printk(KERN_DEBUG - "cannot yet handle multiple different bus clocks!\n"); - return -EINVAL; - } - } - - tmp = ci->transfers; - while (tmp->formats && tmp->rates) { - if (tmp->transfer_in) - in = 1; - else - out = 1; - tmp++; - } - - cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL); - if (!cii) { - printk(KERN_DEBUG "i2sbus: failed to allocate cii\n"); - return -ENOMEM; - } - - /* use the private data to point to the codec info */ - cii->sdev = soundbus_dev_get(dev); - cii->codec = ci; - cii->codec_data = data; - - if (!cii->sdev) { - printk(KERN_DEBUG - "i2sbus: failed to get soundbus dev reference\n"); - err = -ENODEV; - goto out_free_cii; - } - - if (!try_module_get(THIS_MODULE)) { - printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); - err = -EBUSY; - goto out_put_sdev; - } - - if (!try_module_get(ci->owner)) { - printk(KERN_DEBUG - "i2sbus: failed to get module reference to codec owner!\n"); - err = -EBUSY; - goto out_put_this_module; - } - - if (!dev->pcm) { - err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0, - &dev->pcm); - if (err) { - printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); - goto out_put_ci_module; - } - dev->pcm->dev = &dev->ofdev.dev; - } - - /* ALSA yet again sucks. - * If it is ever fixed, remove this line. See below. */ - out = in = 1; - - if (!i2sdev->out.created && out) { - if (dev->pcm->card != card) { - /* eh? */ - printk(KERN_ERR - "Can't attach same bus to different cards!\n"); - err = -EINVAL; - goto out_put_ci_module; - } - err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1); - if (err) - goto out_put_ci_module; - snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, - &i2sbus_playback_ops); - i2sdev->out.created = 1; - } - - if (!i2sdev->in.created && in) { - if (dev->pcm->card != card) { - printk(KERN_ERR - "Can't attach same bus to different cards!\n"); - err = -EINVAL; - goto out_put_ci_module; - } - err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); - if (err) - goto out_put_ci_module; - snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, - &i2sbus_record_ops); - i2sdev->in.created = 1; - } - - /* so we have to register the pcm after adding any substream - * to it because alsa doesn't create the devices for the - * substreams when we add them later. - * Therefore, force in and out on both busses (above) and - * register the pcm now instead of just after creating it. - */ - err = snd_device_register(card, dev->pcm); - if (err) { - printk(KERN_ERR "i2sbus: error registering new pcm\n"); - goto out_put_ci_module; - } - /* no errors any more, so let's add this to our list */ - list_add(&cii->list, &dev->codec_list); - - dev->pcm->private_data = i2sdev; - dev->pcm->private_free = i2sbus_private_free; - - /* well, we really should support scatter/gather DMA */ - snd_pcm_lib_preallocate_pages_for_all( - dev->pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)), - 64 * 1024, 64 * 1024); - - return 0; - out_put_ci_module: - module_put(ci->owner); - out_put_this_module: - module_put(THIS_MODULE); - out_put_sdev: - soundbus_dev_put(dev); - out_free_cii: - kfree(cii); - return err; -} - -void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) -{ - struct codec_info_item *cii = NULL, *i; - - list_for_each_entry(i, &dev->codec_list, list) { - if (i->codec_data == data) { - cii = i; - break; - } - } - if (cii) { - list_del(&cii->list); - module_put(cii->codec->owner); - kfree(cii); - } - /* no more codecs, but still a pcm? */ - if (list_empty(&dev->codec_list) && dev->pcm) { - /* the actual cleanup is done by the callback above! */ - snd_device_free(dev->pcm->card, dev->pcm); - } -} diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/soundbus.h b/ANDROID_3.4.5/sound/aoa/soundbus/soundbus.h deleted file mode 100644 index adecbf36..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/soundbus.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * soundbus generic definitions - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * GPL v2, can be found in COPYING. - */ -#ifndef __SOUNDBUS_H -#define __SOUNDBUS_H - -#include <linux/of_device.h> -#include <sound/pcm.h> -#include <linux/list.h> - - -/* When switching from master to slave or the other way around, - * you don't want to have the codec chip acting as clock source - * while the bus still is. - * More importantly, while switch from slave to master, you need - * to turn off the chip's master function first, but then there's - * no clock for a while and other chips might reset, so we notify - * their drivers after having switched. - * The constants here are codec-point of view, so when we switch - * the soundbus to master we tell the codec we're going to switch - * and give it CLOCK_SWITCH_PREPARE_SLAVE! - */ -enum clock_switch { - CLOCK_SWITCH_PREPARE_SLAVE, - CLOCK_SWITCH_PREPARE_MASTER, - CLOCK_SWITCH_SLAVE, - CLOCK_SWITCH_MASTER, - CLOCK_SWITCH_NOTIFY, -}; - -/* information on a transfer the codec can take */ -struct transfer_info { - u64 formats; /* SNDRV_PCM_FMTBIT_* */ - unsigned int rates; /* SNDRV_PCM_RATE_* */ - /* flags */ - u32 transfer_in:1, /* input = 1, output = 0 */ - must_be_clock_source:1; - /* for codecs to distinguish among their TIs */ - int tag; -}; - -struct codec_info_item { - struct codec_info *codec; - void *codec_data; - struct soundbus_dev *sdev; - /* internal, to be used by the soundbus provider */ - struct list_head list; -}; - -/* for prepare, where the codecs need to know - * what we're going to drive the bus with */ -struct bus_info { - /* see below */ - int sysclock_factor; - int bus_factor; -}; - -/* information on the codec itself, plus function pointers */ -struct codec_info { - /* the module this lives in */ - struct module *owner; - - /* supported transfer possibilities, array terminated by - * formats or rates being 0. */ - struct transfer_info *transfers; - - /* Master clock speed factor - * to be used (master clock speed = sysclock_factor * sampling freq) - * Unused if the soundbus provider has no such notion. - */ - int sysclock_factor; - - /* Bus factor, bus clock speed = bus_factor * sampling freq) - * Unused if the soundbus provider has no such notion. - */ - int bus_factor; - - /* operations */ - /* clock switching, see above */ - int (*switch_clock)(struct codec_info_item *cii, - enum clock_switch clock); - - /* called for each transfer_info when the user - * opens the pcm device to determine what the - * hardware can support at this point in time. - * That can depend on other user-switchable controls. - * Return 1 if usable, 0 if not. - * out points to another instance of a transfer_info - * which is initialised to the values in *ti, and - * it's format and rate values can be modified by - * the callback if it is necessary to further restrict - * the formats that can be used at the moment, for - * example when one codec has multiple logical codec - * info structs for multiple inputs. - */ - int (*usable)(struct codec_info_item *cii, - struct transfer_info *ti, - struct transfer_info *out); - - /* called when pcm stream is opened, probably not implemented - * most of the time since it isn't too useful */ - int (*open)(struct codec_info_item *cii, - struct snd_pcm_substream *substream); - - /* called when the pcm stream is closed, at this point - * the user choices can all be unlocked (see below) */ - int (*close)(struct codec_info_item *cii, - struct snd_pcm_substream *substream); - - /* if the codec must forbid some user choices because - * they are not valid with the substream/transfer info, - * it must do so here. Example: no digital output for - * incompatible framerate, say 8KHz, on Onyx. - * If the selected stuff in the substream is NOT - * compatible, you have to reject this call! */ - int (*prepare)(struct codec_info_item *cii, - struct bus_info *bi, - struct snd_pcm_substream *substream); - - /* start() is called before data is pushed to the codec. - * Note that start() must be atomic! */ - int (*start)(struct codec_info_item *cii, - struct snd_pcm_substream *substream); - - /* stop() is called after data is no longer pushed to the codec. - * Note that stop() must be atomic! */ - int (*stop)(struct codec_info_item *cii, - struct snd_pcm_substream *substream); - - int (*suspend)(struct codec_info_item *cii, pm_message_t state); - int (*resume)(struct codec_info_item *cii); -}; - -/* information on a soundbus device */ -struct soundbus_dev { - /* the bus it belongs to */ - struct list_head onbuslist; - - /* the of device it represents */ - struct platform_device ofdev; - - /* what modules go by */ - char modalias[32]; - - /* These fields must be before attach_codec can be called. - * They should be set by the owner of the alsa card object - * that is needed, and whoever sets them must make sure - * that they are unique within that alsa card object. */ - char *pcmname; - int pcmid; - - /* this is assigned by the soundbus provider in attach_codec */ - struct snd_pcm *pcm; - - /* operations */ - /* attach a codec to this soundbus, give the alsa - * card object the PCMs for this soundbus should be in. - * The 'data' pointer must be unique, it is used as the - * key for detach_codec(). */ - int (*attach_codec)(struct soundbus_dev *dev, struct snd_card *card, - struct codec_info *ci, void *data); - void (*detach_codec)(struct soundbus_dev *dev, void *data); - /* TODO: suspend/resume */ - - /* private for the soundbus provider */ - struct list_head codec_list; - u32 have_out:1, have_in:1; -}; -#define to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev.dev) -#define of_to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev) - -extern int soundbus_add_one(struct soundbus_dev *dev); -extern void soundbus_remove_one(struct soundbus_dev *dev); - -extern struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev); -extern void soundbus_dev_put(struct soundbus_dev *dev); - -struct soundbus_driver { - char *name; - struct module *owner; - - /* we don't implement any matching at all */ - - int (*probe)(struct soundbus_dev* dev); - int (*remove)(struct soundbus_dev* dev); - - int (*suspend)(struct soundbus_dev* dev, pm_message_t state); - int (*resume)(struct soundbus_dev* dev); - int (*shutdown)(struct soundbus_dev* dev); - - struct device_driver driver; -}; -#define to_soundbus_driver(drv) container_of(drv,struct soundbus_driver, driver) - -extern int soundbus_register_driver(struct soundbus_driver *drv); -extern void soundbus_unregister_driver(struct soundbus_driver *drv); - -extern struct device_attribute soundbus_dev_attrs[]; - -#endif /* __SOUNDBUS_H */ diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/sysfs.c b/ANDROID_3.4.5/sound/aoa/soundbus/sysfs.c deleted file mode 100644 index e0980b5c..00000000 --- a/ANDROID_3.4.5/sound/aoa/soundbus/sysfs.c +++ /dev/null @@ -1,42 +0,0 @@ -#include <linux/kernel.h> -#include <linux/stat.h> -/* FIX UP */ -#include "soundbus.h" - -#define soundbus_config_of_attr(field, format_string) \ -static ssize_t \ -field##_show (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct soundbus_dev *mdev = to_soundbus_device (dev); \ - return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \ -} - -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct soundbus_dev *sdev = to_soundbus_device(dev); - struct platform_device *of = &sdev->ofdev; - int length; - - if (*sdev->modalias) { - strlcpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1); - strcat(buf, "\n"); - length = strlen(buf); - } else { - length = sprintf(buf, "of:N%sT%s\n", - of->dev.of_node->name, of->dev.of_node->type); - } - - return length; -} - -soundbus_config_of_attr (name, "%s\n"); -soundbus_config_of_attr (type, "%s\n"); - -struct device_attribute soundbus_dev_attrs[] = { - __ATTR_RO(name), - __ATTR_RO(type), - __ATTR_RO(modalias), - __ATTR_NULL -}; |