Merge branch 'fix/hda' into topic/hda
Conflicts: sound/pci/hda/patch_realtek.c
This commit is contained in:
commit
ffe7e40639
@ -50,8 +50,7 @@ Machine DAI Configuration
|
||||
The machine DAI configuration glues all the codec and CPU DAIs together. It can
|
||||
also be used to set up the DAI system clock and for any machine related DAI
|
||||
initialisation e.g. the machine audio map can be connected to the codec audio
|
||||
map, unconnected codec pins can be set as such. Please see corgi.c, spitz.c
|
||||
for examples.
|
||||
map, unconnected codec pins can be set as such.
|
||||
|
||||
struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
|
||||
|
||||
@ -83,8 +82,7 @@ Machine Power Map
|
||||
The machine driver can optionally extend the codec power map and to become an
|
||||
audio power map of the audio subsystem. This allows for automatic power up/down
|
||||
of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack
|
||||
sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for
|
||||
details.
|
||||
sockets in the machine init function.
|
||||
|
||||
|
||||
Machine Controls
|
||||
|
@ -14,13 +14,34 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/sigma.h>
|
||||
|
||||
/* Return: 0==OK, <0==error, =1 ==no more actions */
|
||||
static int
|
||||
process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
|
||||
static size_t sigma_action_size(struct sigma_action *sa)
|
||||
{
|
||||
size_t payload = 0;
|
||||
|
||||
switch (sa->instr) {
|
||||
case SIGMA_ACTION_WRITEXBYTES:
|
||||
case SIGMA_ACTION_WRITESINGLE:
|
||||
case SIGMA_ACTION_WRITESAFELOAD:
|
||||
payload = sigma_action_len(sa);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
payload = ALIGN(payload, 2);
|
||||
|
||||
return payload + sizeof(struct sigma_action);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a negative error value in case of an error, 0 if processing of
|
||||
* the firmware should be stopped after this action, 1 otherwise.
|
||||
*/
|
||||
static int
|
||||
process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
|
||||
{
|
||||
struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
|
||||
size_t len = sigma_action_len(sa);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
|
||||
sa->instr, sa->addr, len);
|
||||
@ -29,44 +50,50 @@ process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
|
||||
case SIGMA_ACTION_WRITEXBYTES:
|
||||
case SIGMA_ACTION_WRITESINGLE:
|
||||
case SIGMA_ACTION_WRITESAFELOAD:
|
||||
if (ssfw->fw->size < ssfw->pos + len)
|
||||
return -EINVAL;
|
||||
ret = i2c_master_send(client, (void *)&sa->addr, len);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case SIGMA_ACTION_DELAY:
|
||||
ret = 0;
|
||||
udelay(len);
|
||||
len = 0;
|
||||
break;
|
||||
|
||||
case SIGMA_ACTION_END:
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* when arrive here ret=0 or sent data */
|
||||
ssfw->pos += sigma_action_size(sa, len);
|
||||
return ssfw->pos == ssfw->fw->size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
|
||||
{
|
||||
pr_debug("%s: processing %p\n", __func__, ssfw);
|
||||
struct sigma_action *sa;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
|
||||
sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
|
||||
|
||||
size = sigma_action_size(sa);
|
||||
ssfw->pos += size;
|
||||
if (ssfw->pos > ssfw->fw->size || size == 0)
|
||||
break;
|
||||
|
||||
ret = process_sigma_action(client, sa);
|
||||
|
||||
while (1) {
|
||||
int ret = process_sigma_action(client, ssfw);
|
||||
pr_debug("%s: action returned %i\n", __func__, ret);
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
else if (ret)
|
||||
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ssfw->pos != ssfw->fw->size)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_sigma_firmware(struct i2c_client *client, const char *name)
|
||||
@ -89,16 +116,24 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
|
||||
|
||||
/* then verify the header */
|
||||
ret = -EINVAL;
|
||||
if (fw->size < sizeof(*ssfw_head))
|
||||
|
||||
/*
|
||||
* Reject too small or unreasonable large files. The upper limit has been
|
||||
* chosen a bit arbitrarily, but it should be enough for all practical
|
||||
* purposes and having the limit makes it easier to avoid integer
|
||||
* overflows later in the loading process.
|
||||
*/
|
||||
if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000)
|
||||
goto done;
|
||||
|
||||
ssfw_head = (void *)fw->data;
|
||||
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
|
||||
goto done;
|
||||
|
||||
crc = crc32(0, fw->data, fw->size);
|
||||
crc = crc32(0, fw->data + sizeof(*ssfw_head),
|
||||
fw->size - sizeof(*ssfw_head));
|
||||
pr_debug("%s: crc=%x\n", __func__, crc);
|
||||
if (crc != ssfw_head->crc)
|
||||
if (crc != le32_to_cpu(ssfw_head->crc))
|
||||
goto done;
|
||||
|
||||
ssfw.pos = sizeof(*ssfw_head);
|
||||
|
@ -24,7 +24,7 @@ struct sigma_firmware {
|
||||
struct sigma_firmware_header {
|
||||
unsigned char magic[7];
|
||||
u8 version;
|
||||
u32 crc;
|
||||
__le32 crc;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -40,19 +40,14 @@ enum {
|
||||
struct sigma_action {
|
||||
u8 instr;
|
||||
u8 len_hi;
|
||||
u16 len;
|
||||
u16 addr;
|
||||
__le16 len;
|
||||
__be16 addr;
|
||||
unsigned char payload[];
|
||||
};
|
||||
|
||||
static inline u32 sigma_action_len(struct sigma_action *sa)
|
||||
{
|
||||
return (sa->len_hi << 16) | sa->len;
|
||||
}
|
||||
|
||||
static inline size_t sigma_action_size(struct sigma_action *sa, u32 payload_len)
|
||||
{
|
||||
return sizeof(*sa) + payload_len + (payload_len % 2);
|
||||
return (sa->len_hi << 16) | le16_to_cpu(sa->len);
|
||||
}
|
||||
|
||||
extern int process_sigma_firmware(struct i2c_client *client, const char *name);
|
||||
|
@ -300,6 +300,8 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
||||
imux = &spec->input_mux[mux_idx];
|
||||
if (!imux->num_items && mux_idx > 0)
|
||||
imux = &spec->input_mux[0];
|
||||
if (!imux->num_items)
|
||||
return 0;
|
||||
|
||||
if (idx >= imux->num_items)
|
||||
idx = imux->num_items - 1;
|
||||
@ -2663,6 +2665,8 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
|
||||
case AUTO_PIN_SPEAKER_OUT:
|
||||
if (cfg->line_outs == 1)
|
||||
return "Speaker";
|
||||
if (cfg->line_outs == 2)
|
||||
return ch ? "Bass Speaker" : "Speaker";
|
||||
break;
|
||||
case AUTO_PIN_HP_OUT:
|
||||
/* for multi-io case, only the primary out */
|
||||
@ -2974,7 +2978,7 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
|
||||
if (!nid)
|
||||
continue;
|
||||
if (found_in_nid_list(nid, spec->multiout.dac_nids,
|
||||
spec->multiout.num_dacs))
|
||||
ARRAY_SIZE(spec->private_dac_nids)))
|
||||
continue;
|
||||
if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
|
||||
ARRAY_SIZE(spec->multiout.hp_out_nid)))
|
||||
@ -3012,6 +3016,7 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return 0 if no possible DAC is found, 1 if one or more found */
|
||||
static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
|
||||
const hda_nid_t *pins, hda_nid_t *dacs)
|
||||
{
|
||||
@ -3029,7 +3034,7 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
|
||||
if (!dacs[i])
|
||||
dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
||||
@ -3039,7 +3044,7 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
||||
static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int location, defcfg;
|
||||
int num_pins;
|
||||
bool redone = false;
|
||||
@ -3052,6 +3057,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||
spec->multiout.extra_out_nid[0] = 0;
|
||||
memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
|
||||
spec->multiout.dac_nids = spec->private_dac_nids;
|
||||
spec->multi_ios = 0;
|
||||
|
||||
/* fill hard-wired DACs first */
|
||||
if (!redone) {
|
||||
@ -3085,10 +3091,12 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||
for (i = 0; i < cfg->line_outs; i++) {
|
||||
if (spec->private_dac_nids[i])
|
||||
spec->multiout.num_dacs++;
|
||||
else
|
||||
else {
|
||||
memmove(spec->private_dac_nids + i,
|
||||
spec->private_dac_nids + i + 1,
|
||||
sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
|
||||
spec->private_dac_nids[cfg->line_outs - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||
@ -3107,9 +3115,28 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||
if (cfg->line_out_type != AUTO_PIN_HP_OUT)
|
||||
alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
|
||||
spec->multiout.hp_out_nid);
|
||||
if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
|
||||
alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins,
|
||||
spec->multiout.extra_out_nid);
|
||||
if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||
int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
|
||||
cfg->speaker_pins,
|
||||
spec->multiout.extra_out_nid);
|
||||
/* if no speaker volume is assigned, try again as the primary
|
||||
* output
|
||||
*/
|
||||
if (!err && cfg->speaker_outs > 0 &&
|
||||
cfg->line_out_type == AUTO_PIN_HP_OUT) {
|
||||
cfg->hp_outs = cfg->line_outs;
|
||||
memcpy(cfg->hp_pins, cfg->line_out_pins,
|
||||
sizeof(cfg->hp_pins));
|
||||
cfg->line_outs = cfg->speaker_outs;
|
||||
memcpy(cfg->line_out_pins, cfg->speaker_pins,
|
||||
sizeof(cfg->speaker_pins));
|
||||
cfg->speaker_outs = 0;
|
||||
memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
|
||||
cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
|
||||
redone = false;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spec->multi_ios &&
|
||||
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
|
||||
@ -3287,7 +3314,8 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
|
||||
}
|
||||
|
||||
static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
|
||||
hda_nid_t dac, const char *pfx)
|
||||
hda_nid_t dac, const char *pfx,
|
||||
int cidx)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
hda_nid_t sw, vol;
|
||||
@ -3303,15 +3331,15 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
|
||||
if (is_ctl_used(spec->sw_ctls, val))
|
||||
return 0; /* already created */
|
||||
mark_ctl_usage(spec->sw_ctls, val);
|
||||
return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
|
||||
return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val);
|
||||
}
|
||||
|
||||
sw = alc_look_for_out_mute_nid(codec, pin, dac);
|
||||
vol = alc_look_for_out_vol_nid(codec, pin, dac);
|
||||
err = alc_auto_add_stereo_vol(codec, pfx, 0, vol);
|
||||
err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = alc_auto_add_stereo_sw(codec, pfx, 0, sw);
|
||||
err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
@ -3352,16 +3380,21 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
|
||||
hda_nid_t dac = *dacs;
|
||||
if (!dac)
|
||||
dac = spec->multiout.dac_nids[0];
|
||||
return alc_auto_create_extra_out(codec, *pins, dac, pfx);
|
||||
return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
|
||||
}
|
||||
|
||||
if (dacs[num_pins - 1]) {
|
||||
/* OK, we have a multi-output system with individual volumes */
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
snprintf(name, sizeof(name), "%s %s",
|
||||
pfx, channel_name[i]);
|
||||
err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
|
||||
name);
|
||||
if (num_pins >= 3) {
|
||||
snprintf(name, sizeof(name), "%s %s",
|
||||
pfx, channel_name[i]);
|
||||
err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
|
||||
name, 0);
|
||||
} else {
|
||||
err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
|
||||
pfx, i);
|
||||
}
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -215,6 +215,7 @@ struct sigmatel_spec {
|
||||
unsigned int gpio_mute;
|
||||
unsigned int gpio_led;
|
||||
unsigned int gpio_led_polarity;
|
||||
unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
|
||||
unsigned int vref_led;
|
||||
|
||||
/* stream */
|
||||
@ -4318,12 +4319,10 @@ static void stac_store_hints(struct hda_codec *codec)
|
||||
spec->eapd_switch = val;
|
||||
get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
|
||||
if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
|
||||
if (spec->gpio_led <= 8) {
|
||||
spec->gpio_mask |= spec->gpio_led;
|
||||
spec->gpio_dir |= spec->gpio_led;
|
||||
if (spec->gpio_led_polarity)
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
}
|
||||
spec->gpio_mask |= spec->gpio_led;
|
||||
spec->gpio_dir |= spec->gpio_led;
|
||||
if (spec->gpio_led_polarity)
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4443,7 +4442,7 @@ static int stac92xx_init(struct hda_codec *codec)
|
||||
/* power on when no jack detection is available */
|
||||
/* or when the VREF is used for controlling LED */
|
||||
if (!spec->hp_detect ||
|
||||
(spec->gpio_led > 8 && spec->gpio_led == nid)) {
|
||||
spec->vref_mute_led_nid == nid) {
|
||||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
@ -4915,8 +4914,14 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
|
||||
if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
|
||||
&spec->gpio_led_polarity,
|
||||
&spec->gpio_led) == 2) {
|
||||
if (spec->gpio_led < 4)
|
||||
unsigned int max_gpio;
|
||||
max_gpio = snd_hda_param_read(codec, codec->afg,
|
||||
AC_PAR_GPIO_CAP);
|
||||
max_gpio &= AC_GPIO_IO_COUNT;
|
||||
if (spec->gpio_led < max_gpio)
|
||||
spec->gpio_led = 1 << spec->gpio_led;
|
||||
else
|
||||
spec->vref_mute_led_nid = spec->gpio_led;
|
||||
return 1;
|
||||
}
|
||||
if (sscanf(dev->name, "HP_Mute_LED_%d",
|
||||
@ -5045,15 +5050,12 @@ static int stac92xx_pre_resume(struct hda_codec *codec)
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led) {
|
||||
if (spec->gpio_led <= 8) {
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
spec->gpio_dir, spec->gpio_data);
|
||||
} else {
|
||||
stac_vrefout_set(codec,
|
||||
spec->gpio_led, spec->vref_led);
|
||||
}
|
||||
}
|
||||
if (spec->vref_mute_led_nid)
|
||||
stac_vrefout_set(codec, spec->vref_mute_led_nid,
|
||||
spec->vref_led);
|
||||
else if (spec->gpio_led)
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
spec->gpio_dir, spec->gpio_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5064,7 +5066,7 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
if (power_state == AC_PWRST_D3) {
|
||||
if (spec->gpio_led > 8) {
|
||||
if (spec->vref_mute_led_nid) {
|
||||
/* with vref-out pin used for mute led control
|
||||
* codec AFG is prevented from D3 state
|
||||
*/
|
||||
@ -5117,7 +5119,7 @@ static int stac92xx_update_led_status(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
/*polarity defines *not* muted state level*/
|
||||
if (spec->gpio_led <= 8) {
|
||||
if (!spec->vref_mute_led_nid) {
|
||||
if (muted)
|
||||
spec->gpio_data &= ~spec->gpio_led; /* orange */
|
||||
else
|
||||
@ -5135,7 +5137,8 @@ static int stac92xx_update_led_status(struct hda_codec *codec)
|
||||
muted_lvl = spec->gpio_led_polarity ?
|
||||
AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_HIZ;
|
||||
spec->vref_led = muted ? muted_lvl : notmtd_lvl;
|
||||
stac_vrefout_set(codec, spec->gpio_led, spec->vref_led);
|
||||
stac_vrefout_set(codec, spec->vref_mute_led_nid,
|
||||
spec->vref_led);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -5649,7 +5652,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (spec->gpio_led) {
|
||||
if (spec->gpio_led <= 8) {
|
||||
if (!spec->vref_mute_led_nid) {
|
||||
spec->gpio_mask |= spec->gpio_led;
|
||||
spec->gpio_dir |= spec->gpio_led;
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
@ -5962,7 +5965,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (spec->gpio_led) {
|
||||
if (spec->gpio_led <= 8) {
|
||||
if (!spec->vref_mute_led_nid) {
|
||||
spec->gpio_mask |= spec->gpio_led;
|
||||
spec->gpio_dir |= spec->gpio_led;
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
|
@ -41,6 +41,7 @@ MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}");
|
||||
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
|
||||
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
|
||||
static int enable = 1;
|
||||
static int codecs = 1;
|
||||
|
||||
module_param(index, int, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator.");
|
||||
@ -48,6 +49,8 @@ module_param(id, charp, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
|
||||
module_param(enable, bool, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
|
||||
module_param(codecs, int, 0444);
|
||||
MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)");
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
|
||||
@ -140,6 +143,9 @@ struct sis7019 {
|
||||
dma_addr_t silence_dma_addr;
|
||||
};
|
||||
|
||||
/* These values are also used by the module param 'codecs' to indicate
|
||||
* which codecs should be present.
|
||||
*/
|
||||
#define SIS_PRIMARY_CODEC_PRESENT 0x0001
|
||||
#define SIS_SECONDARY_CODEC_PRESENT 0x0002
|
||||
#define SIS_TERTIARY_CODEC_PRESENT 0x0004
|
||||
@ -1078,6 +1084,7 @@ static int sis_chip_init(struct sis7019 *sis)
|
||||
{
|
||||
unsigned long io = sis->ioport;
|
||||
void __iomem *ioaddr = sis->ioaddr;
|
||||
unsigned long timeout;
|
||||
u16 status;
|
||||
int count;
|
||||
int i;
|
||||
@ -1104,22 +1111,46 @@ static int sis_chip_init(struct sis7019 *sis)
|
||||
while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
|
||||
udelay(1);
|
||||
|
||||
/* Now that we've finished the reset, find out what's attached.
|
||||
*/
|
||||
status = inl(io + SIS_AC97_STATUS);
|
||||
if (status & SIS_AC97_STATUS_CODEC_READY)
|
||||
sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC2_READY)
|
||||
sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC3_READY)
|
||||
sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
|
||||
|
||||
/* All done, let go of the semaphore, and check for errors
|
||||
/* Command complete, we can let go of the semaphore now.
|
||||
*/
|
||||
outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
|
||||
if (!sis->codecs_present || !count)
|
||||
if (!count)
|
||||
return -EIO;
|
||||
|
||||
/* Now that we've finished the reset, find out what's attached.
|
||||
* There are some codec/board combinations that take an extremely
|
||||
* long time to come up. 350+ ms has been observed in the field,
|
||||
* so we'll give them up to 500ms.
|
||||
*/
|
||||
sis->codecs_present = 0;
|
||||
timeout = msecs_to_jiffies(500) + jiffies;
|
||||
while (time_before_eq(jiffies, timeout)) {
|
||||
status = inl(io + SIS_AC97_STATUS);
|
||||
if (status & SIS_AC97_STATUS_CODEC_READY)
|
||||
sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC2_READY)
|
||||
sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
|
||||
if (status & SIS_AC97_STATUS_CODEC3_READY)
|
||||
sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
|
||||
|
||||
if (sis->codecs_present == codecs)
|
||||
break;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
/* All done, check for errors.
|
||||
*/
|
||||
if (!sis->codecs_present) {
|
||||
printk(KERN_ERR "sis7019: could not find any codecs\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (sis->codecs_present != codecs) {
|
||||
printk(KERN_WARNING "sis7019: missing codecs, found %0x, expected %0x\n",
|
||||
sis->codecs_present, codecs);
|
||||
}
|
||||
|
||||
/* Let the hardware know that the audio driver is alive,
|
||||
* and enable PCM slots on the AC-link for L/R playback (3 & 4) and
|
||||
* record channels. We're going to want to use Variable Rate Audio
|
||||
@ -1390,6 +1421,17 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci,
|
||||
if (!enable)
|
||||
goto error_out;
|
||||
|
||||
/* The user can specify which codecs should be present so that we
|
||||
* can wait for them to show up if they are slow to recover from
|
||||
* the AC97 cold reset. We default to a single codec, the primary.
|
||||
*
|
||||
* We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2.
|
||||
*/
|
||||
codecs &= SIS_PRIMARY_CODEC_PRESENT | SIS_SECONDARY_CODEC_PRESENT |
|
||||
SIS_TERTIARY_CODEC_PRESENT;
|
||||
if (!codecs)
|
||||
codecs = SIS_PRIMARY_CODEC_PRESENT;
|
||||
|
||||
rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
|
||||
if (rc < 0)
|
||||
goto error_out;
|
||||
|
@ -1,6 +1,6 @@
|
||||
config SND_ATMEL_SOC
|
||||
tristate "SoC Audio for the Atmel System-on-Chip"
|
||||
depends on ARCH_AT91 || AVR32
|
||||
depends on ARCH_AT91
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the ATMEL SSC interface. You will also need
|
||||
@ -24,25 +24,6 @@ config SND_AT91_SOC_SAM9G20_WM8731
|
||||
Say Y if you want to add support for SoC audio on WM8731-based
|
||||
AT91sam9g20 evaluation board.
|
||||
|
||||
config SND_AT32_SOC_PLAYPAQ
|
||||
tristate "SoC Audio support for PlayPaq with WM8510"
|
||||
depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS
|
||||
select SND_ATMEL_SOC_SSC
|
||||
select SND_SOC_WM8510
|
||||
help
|
||||
Say Y or M here if you want to add support for SoC audio
|
||||
on the LRS PlayPaq.
|
||||
|
||||
config SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
bool "Run CODEC on PlayPaq in slave mode"
|
||||
depends on SND_AT32_SOC_PLAYPAQ
|
||||
default n
|
||||
help
|
||||
Say Y if you want to run with the AT32 SSC generating the BCLK
|
||||
and FRAME signals on the PlayPaq. Unless you want to play
|
||||
with the AT32 as the SSC master, you probably want to say N here,
|
||||
as this will give you better sound quality.
|
||||
|
||||
config SND_AT91_SOC_AFEB9260
|
||||
tristate "SoC Audio support for AFEB9260 board"
|
||||
depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
|
||||
|
@ -8,9 +8,5 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
|
||||
# AT91 Machine Support
|
||||
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
|
||||
|
||||
# AT32 Machine Support
|
||||
snd-soc-playpaq-objs := playpaq_wm8510.o
|
||||
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
|
||||
|
@ -1,473 +0,0 @@
|
||||
/* sound/soc/at32/playpaq_wm8510.c
|
||||
* ASoC machine driver for PlayPaq using WM8510 codec
|
||||
*
|
||||
* Copyright (C) 2008 Long Range Systems
|
||||
* Geoffrey Wossum <gwossum@acm.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c
|
||||
*
|
||||
* NOTE: If you don't have the AT32 enhanced portmux configured (which
|
||||
* isn't currently in the mainline or Atmel patched kernel), you will
|
||||
* need to set the MCLK pin (PA30) to peripheral A in your board initialization
|
||||
* code. Something like:
|
||||
* at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
|
||||
*
|
||||
*/
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <mach/at32ap700x.h>
|
||||
#include <mach/portmux.h>
|
||||
|
||||
#include "../codecs/wm8510.h"
|
||||
#include "atmel-pcm.h"
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* constants
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define MCLK_PIN GPIO_PIN_PA(30)
|
||||
#define MCLK_PERIPH GPIO_PERIPH_A
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* data types
|
||||
\*-------------------------------------------------------------------------*/
|
||||
/* SSC clocking data */
|
||||
struct ssc_clock_data {
|
||||
/* CMR div */
|
||||
unsigned int cmr_div;
|
||||
|
||||
/* Frame period (as needed by xCMR.PERIOD) */
|
||||
unsigned int period;
|
||||
|
||||
/* The SSC clock rate these settings where calculated for */
|
||||
unsigned long ssc_rate;
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* module data
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static struct clk *_gclk0;
|
||||
static struct clk *_pll0;
|
||||
|
||||
#define CODEC_CLK (_gclk0)
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sound SOC operations
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
struct ssc_clock_data cd;
|
||||
unsigned int rate, width_bits, channels;
|
||||
unsigned int bitrate, ssc_div;
|
||||
unsigned actual_rate;
|
||||
|
||||
|
||||
/*
|
||||
* Figure out required bitrate
|
||||
*/
|
||||
rate = params_rate(params);
|
||||
channels = params_channels(params);
|
||||
width_bits = snd_pcm_format_physical_width(params_format(params));
|
||||
bitrate = rate * width_bits * channels;
|
||||
|
||||
|
||||
/*
|
||||
* Figure out required SSC divider and period for required bitrate
|
||||
*/
|
||||
cd.ssc_rate = clk_get_rate(ssc->clk);
|
||||
ssc_div = cd.ssc_rate / bitrate;
|
||||
cd.cmr_div = ssc_div / 2;
|
||||
if (ssc_div & 1) {
|
||||
/* round cmr_div up */
|
||||
cd.cmr_div++;
|
||||
}
|
||||
cd.period = width_bits - 1;
|
||||
|
||||
|
||||
/*
|
||||
* Find actual rate, compare to requested rate
|
||||
*/
|
||||
actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1));
|
||||
pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n",
|
||||
rate, actual_rate);
|
||||
|
||||
|
||||
return cd;
|
||||
}
|
||||
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
|
||||
|
||||
|
||||
|
||||
static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
|
||||
int ret;
|
||||
|
||||
|
||||
/* Due to difficulties with getting the correct clocks from the AT32's
|
||||
* PLL0, we're going to let the CODEC be in charge of all the clocks
|
||||
*/
|
||||
#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
const unsigned int fmt = (SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM);
|
||||
#else
|
||||
struct ssc_clock_data cd;
|
||||
const unsigned int fmt = (SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
#endif
|
||||
|
||||
if (ssc == NULL) {
|
||||
pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Figure out PLL and BCLK dividers for WM8510
|
||||
*/
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
pll_out = 24576000;
|
||||
mclk_div = WM8510_MCLKDIV_2;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 44100:
|
||||
pll_out = 22579200;
|
||||
mclk_div = WM8510_MCLKDIV_2;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 22050:
|
||||
pll_out = 22579200;
|
||||
mclk_div = WM8510_MCLKDIV_4;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 16000:
|
||||
pll_out = 24576000;
|
||||
mclk_div = WM8510_MCLKDIV_6;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 11025:
|
||||
pll_out = 22579200;
|
||||
mclk_div = WM8510_MCLKDIV_8;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
case 8000:
|
||||
pll_out = 24576000;
|
||||
mclk_div = WM8510_MCLKDIV_12;
|
||||
bclk = WM8510_BCLKDIV_8;
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_warning("playpaq_wm8510: Unsupported sample rate %d\n",
|
||||
params_rate(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* set CPU and CODEC DAI configuration
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, fmt);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: "
|
||||
"Failed to set CODEC DAI format (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: "
|
||||
"Failed to set CPU DAI format (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set CPU clock configuration
|
||||
*/
|
||||
#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai);
|
||||
pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n",
|
||||
cd.cmr_div, cd.period);
|
||||
ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD,
|
||||
cd.period);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: "
|
||||
"Failed to set CPU transmit period (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
|
||||
|
||||
|
||||
/*
|
||||
* Set CODEC clock configuration
|
||||
*/
|
||||
pr_debug("playpaq_wm8510: "
|
||||
"pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n",
|
||||
clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div);
|
||||
|
||||
|
||||
#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
|
||||
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk);
|
||||
if (ret < 0) {
|
||||
pr_warning
|
||||
("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
|
||||
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, 0,
|
||||
clk_get_rate(CODEC_CLK), pll_out);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div);
|
||||
if (ret < 0) {
|
||||
pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_ops playpaq_wm8510_ops = {
|
||||
.hw_params = playpaq_wm8510_hw_params,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const struct snd_soc_dapm_route intercon[] = {
|
||||
/* speaker connected to SPKOUT */
|
||||
{"Ext Spk", NULL, "SPKOUTP"},
|
||||
{"Ext Spk", NULL, "SPKOUTN"},
|
||||
|
||||
{"Mic Bias", NULL, "Int Mic"},
|
||||
{"MICN", NULL, "Mic Bias"},
|
||||
{"MICP", NULL, "Mic Bias"},
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Add DAPM widgets
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++)
|
||||
snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Setup audio path interconnects
|
||||
*/
|
||||
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
|
||||
|
||||
/* always connected pins */
|
||||
snd_soc_dapm_enable_pin(dapm, "Int Mic");
|
||||
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
|
||||
|
||||
|
||||
|
||||
/* Make CSB show PLL rate */
|
||||
snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
|
||||
WM8510_OPCLKDIV_1 | 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_dai_link playpaq_wm8510_dai = {
|
||||
.name = "WM8510",
|
||||
.stream_name = "WM8510 PCM",
|
||||
.cpu_dai_name= "atmel-ssc-dai.0",
|
||||
.platform_name = "atmel-pcm-audio",
|
||||
.codec_name = "wm8510-codec.0-0x1a",
|
||||
.codec_dai_name = "wm8510-hifi",
|
||||
.init = playpaq_wm8510_init,
|
||||
.ops = &playpaq_wm8510_ops,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct snd_soc_card snd_soc_playpaq = {
|
||||
.name = "LRS_PlayPaq_WM8510",
|
||||
.dai_link = &playpaq_wm8510_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *playpaq_snd_device;
|
||||
|
||||
|
||||
static int __init playpaq_asoc_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Configure MCLK for WM8510
|
||||
*/
|
||||
_gclk0 = clk_get(NULL, "gclk0");
|
||||
if (IS_ERR(_gclk0)) {
|
||||
_gclk0 = NULL;
|
||||
ret = PTR_ERR(_gclk0);
|
||||
goto err_gclk0;
|
||||
}
|
||||
_pll0 = clk_get(NULL, "pll0");
|
||||
if (IS_ERR(_pll0)) {
|
||||
_pll0 = NULL;
|
||||
ret = PTR_ERR(_pll0);
|
||||
goto err_pll0;
|
||||
}
|
||||
ret = clk_set_parent(_gclk0, _pll0);
|
||||
if (ret) {
|
||||
pr_warning("snd-soc-playpaq: "
|
||||
"Failed to set PLL0 as parent for DAC clock\n");
|
||||
goto err_set_clk;
|
||||
}
|
||||
clk_set_rate(CODEC_CLK, 12000000);
|
||||
clk_enable(CODEC_CLK);
|
||||
|
||||
#if defined CONFIG_AT32_ENHANCED_PORTMUX
|
||||
at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Create and register platform device
|
||||
*/
|
||||
playpaq_snd_device = platform_device_alloc("soc-audio", 0);
|
||||
if (playpaq_snd_device == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_device_alloc;
|
||||
}
|
||||
|
||||
platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
|
||||
|
||||
ret = platform_device_add(playpaq_snd_device);
|
||||
if (ret) {
|
||||
pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n",
|
||||
ret);
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
err_device_add:
|
||||
if (playpaq_snd_device != NULL) {
|
||||
platform_device_put(playpaq_snd_device);
|
||||
playpaq_snd_device = NULL;
|
||||
}
|
||||
err_device_alloc:
|
||||
err_set_clk:
|
||||
if (_pll0 != NULL) {
|
||||
clk_put(_pll0);
|
||||
_pll0 = NULL;
|
||||
}
|
||||
err_pll0:
|
||||
if (_gclk0 != NULL) {
|
||||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void __exit playpaq_asoc_exit(void)
|
||||
{
|
||||
if (_gclk0 != NULL) {
|
||||
clk_put(_gclk0);
|
||||
_gclk0 = NULL;
|
||||
}
|
||||
if (_pll0 != NULL) {
|
||||
clk_put(_pll0);
|
||||
_pll0 = NULL;
|
||||
}
|
||||
|
||||
#if defined CONFIG_AT32_ENHANCED_PORTMUX
|
||||
at32_free_pin(MCLK_PIN);
|
||||
#endif
|
||||
|
||||
platform_device_unregister(playpaq_snd_device);
|
||||
playpaq_snd_device = NULL;
|
||||
}
|
||||
|
||||
module_init(playpaq_asoc_init);
|
||||
module_exit(playpaq_asoc_exit);
|
||||
|
||||
MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
|
||||
MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq");
|
||||
MODULE_LICENSE("GPL");
|
@ -34,7 +34,7 @@
|
||||
|
||||
#define AD1836_ADC_CTRL2 13
|
||||
#define AD1836_ADC_WORD_LEN_MASK 0x30
|
||||
#define AD1836_ADC_WORD_OFFSET 5
|
||||
#define AD1836_ADC_WORD_OFFSET 4
|
||||
#define AD1836_ADC_SERFMT_MASK (7 << 6)
|
||||
#define AD1836_ADC_SERFMT_PCK256 (0x4 << 6)
|
||||
#define AD1836_ADC_SERFMT_PCK128 (0x5 << 6)
|
||||
|
@ -601,7 +601,6 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
|
||||
static int cs4270_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c_client = to_i2c_client(codec->dev);
|
||||
int reg;
|
||||
|
||||
regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
|
||||
@ -612,14 +611,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
|
||||
ndelay(500);
|
||||
|
||||
/* first restore the entire register cache ... */
|
||||
for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) {
|
||||
u8 val = snd_soc_read(codec, reg);
|
||||
|
||||
if (i2c_smbus_write_byte_data(i2c_client, reg, val)) {
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
snd_soc_cache_sync(codec);
|
||||
|
||||
/* ... then disable the power-down bits */
|
||||
reg = snd_soc_read(codec, CS4270_PWRCTL);
|
||||
|
@ -555,7 +555,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
|
||||
.probe = cs42l51_probe,
|
||||
.reg_cache_size = CS42L51_NUMREGS,
|
||||
.reg_cache_size = CS42L51_NUMREGS + 1,
|
||||
.reg_word_size = sizeof(u8),
|
||||
};
|
||||
|
||||
|
@ -106,13 +106,13 @@ static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
|
||||
unsigned int mask = mc->max;
|
||||
unsigned int val = (ucontrol->value.integer.value[0] & mask);
|
||||
unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
|
||||
unsigned int change = 1;
|
||||
unsigned int change = 0;
|
||||
|
||||
if (((max9877_regs[reg] >> shift) & mask) == val)
|
||||
change = 0;
|
||||
if (((max9877_regs[reg] >> shift) & mask) != val)
|
||||
change = 1;
|
||||
|
||||
if (((max9877_regs[reg2] >> shift) & mask) == val2)
|
||||
change = 0;
|
||||
if (((max9877_regs[reg2] >> shift) & mask) != val2)
|
||||
change = 1;
|
||||
|
||||
if (change) {
|
||||
max9877_regs[reg] &= ~(mask << shift);
|
||||
|
@ -863,13 +863,13 @@ static struct i2c_driver uda1380_i2c_driver = {
|
||||
|
||||
static int __init uda1380_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&uda1380_i2c_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
|
||||
#endif
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
module_init(uda1380_modinit);
|
||||
|
||||
|
@ -1325,15 +1325,15 @@ SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = {
|
||||
SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
|
||||
adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
|
||||
SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
|
||||
adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
|
||||
SND_SOC_DAPM_VIRT_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
|
||||
adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
|
||||
SND_SOC_DAPM_VIRT_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
|
||||
adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
|
||||
SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
|
||||
SND_SOC_DAPM_VIRT_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
|
||||
SND_SOC_DAPM_VIRT_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
|
||||
@ -2357,6 +2357,11 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
||||
bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
|
||||
|
||||
lrclk = bclk_rate / params_rate(params);
|
||||
if (!lrclk) {
|
||||
dev_err(dai->dev, "Unable to generate LRCLK from %dHz BCLK\n",
|
||||
bclk_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
|
||||
lrclk, bclk_rate / lrclk);
|
||||
|
||||
@ -3178,6 +3183,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
switch (wm8994->revision) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
wm8994->hubs.dcs_codes_l = -9;
|
||||
wm8994->hubs.dcs_codes_r = -5;
|
||||
break;
|
||||
|
@ -392,7 +392,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (strcasecmp(sprop, "i2s-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_I2S;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
|
||||
@ -409,31 +410,38 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
|
||||
}
|
||||
machine_data->clk_frequency = be32_to_cpup(iprop);
|
||||
} else if (strcasecmp(sprop, "i2s-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_I2S;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else if (strcasecmp(sprop, "lj-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
} else if (strcasecmp(sprop, "lj-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else if (strcasecmp(sprop, "rj-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
} else if (strcasecmp(sprop, "rj-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else if (strcasecmp(sprop, "ac97-slave") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_AC97;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
|
||||
} else if (strcasecmp(sprop, "ac97-master") == 0) {
|
||||
machine_data->dai_format = SND_SOC_DAIFMT_AC97;
|
||||
machine_data->dai_format =
|
||||
SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS;
|
||||
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
|
||||
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
|
||||
} else {
|
||||
|
@ -28,7 +28,7 @@ config SND_MXC_SOC_WM1133_EV1
|
||||
|
||||
config SND_SOC_MX27VIS_AIC32X4
|
||||
tristate "SoC audio support for Visstrim M10 boards"
|
||||
depends on MACH_IMX27_VISSTRIM_M10
|
||||
depends on MACH_IMX27_VISSTRIM_M10 && I2C
|
||||
select SND_SOC_TLV320AIC32X4
|
||||
select SND_MXC_SOC_MX2
|
||||
help
|
||||
|
@ -12,6 +12,7 @@ config SND_KIRKWOOD_SOC_I2S
|
||||
config SND_KIRKWOOD_SOC_OPENRD
|
||||
tristate "SoC Audio support for Kirkwood Openrd Client"
|
||||
depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE)
|
||||
depends on I2C
|
||||
select SND_KIRKWOOD_SOC_I2S
|
||||
select SND_SOC_CS42L51
|
||||
help
|
||||
@ -20,7 +21,7 @@ config SND_KIRKWOOD_SOC_OPENRD
|
||||
|
||||
config SND_KIRKWOOD_SOC_T5325
|
||||
tristate "SoC Audio support for HP t5325"
|
||||
depends on SND_KIRKWOOD_SOC && MACH_T5325
|
||||
depends on SND_KIRKWOOD_SOC && MACH_T5325 && I2C
|
||||
select SND_KIRKWOOD_SOC_I2S
|
||||
select SND_SOC_ALC5623
|
||||
help
|
||||
|
@ -151,6 +151,7 @@ config SND_SOC_ZYLONITE
|
||||
config SND_SOC_RAUMFELD
|
||||
tristate "SoC Audio support Raumfeld audio adapter"
|
||||
depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR)
|
||||
depends on I2C && SPI_MASTER
|
||||
select SND_PXA_SOC_SSP
|
||||
select SND_SOC_CS4270
|
||||
select SND_SOC_AK4104
|
||||
@ -159,7 +160,7 @@ config SND_SOC_RAUMFELD
|
||||
|
||||
config SND_PXA2XX_SOC_HX4700
|
||||
tristate "SoC Audio support for HP iPAQ hx4700"
|
||||
depends on SND_PXA2XX_SOC && MACH_H4700
|
||||
depends on SND_PXA2XX_SOC && MACH_H4700 && I2C
|
||||
select SND_PXA2XX_SOC_I2S
|
||||
select SND_SOC_AK4641
|
||||
help
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "../codecs/wm8994.h"
|
||||
#include <sound/pcm_params.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Default CFG switch settings to use this driver:
|
||||
|
@ -191,7 +191,7 @@ static int speyside_late_probe(struct snd_soc_card *card)
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "Main Speaker");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output");
|
||||
snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input");
|
||||
|
||||
|
@ -709,6 +709,12 @@ int snd_soc_resume(struct device *dev)
|
||||
struct snd_soc_card *card = dev_get_drvdata(dev);
|
||||
int i, ac97_control = 0;
|
||||
|
||||
/* If the initialization of this soc device failed, there is no codec
|
||||
* associated with it. Just bail out in this case.
|
||||
*/
|
||||
if (list_empty(&card->codec_dev_list))
|
||||
return 0;
|
||||
|
||||
/* AC97 devices might have other drivers hanging off them so
|
||||
* need to resume immediately. Other drivers don't have that
|
||||
* problem and may take a substantial amount of time to resume
|
||||
|
@ -58,7 +58,36 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
|
||||
|
||||
static struct snd_soc_platform_driver dummy_platform;
|
||||
static const struct snd_pcm_hardware dummy_dma_hardware = {
|
||||
.formats = 0xffffffff,
|
||||
.channels_min = 1,
|
||||
.channels_max = UINT_MAX,
|
||||
|
||||
/* Random values to keep userspace happy when checking constraints */
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||
.buffer_bytes_max = 128*1024,
|
||||
.period_bytes_min = PAGE_SIZE,
|
||||
.period_bytes_max = PAGE_SIZE*2,
|
||||
.periods_min = 2,
|
||||
.periods_max = 128,
|
||||
};
|
||||
|
||||
static int dummy_dma_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops dummy_dma_ops = {
|
||||
.open = dummy_dma_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
};
|
||||
|
||||
static struct snd_soc_platform_driver dummy_platform = {
|
||||
.ops = &dummy_dma_ops,
|
||||
};
|
||||
|
||||
static __devinit int snd_soc_dummy_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user