Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ffe7e406 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'fix/hda' into topic/hda

Conflicts:
	sound/pci/hda/patch_realtek.c
parents 9eb6e9b1 0a34b42b
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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
+58 −23
Original line number Diff line number Diff line
@@ -14,13 +14,34 @@
#include <linux/module.h>
#include <linux/sigma.h>

/* Return: 0==OK, <0==error, =1 ==no more actions */
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_firmware *ssfw)
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);
+4 −9
Original line number Diff line number Diff line
@@ -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);
+49 −16
Original line number Diff line number Diff line
@@ -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,
	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++) {
			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);
								name, 0);
			} else {
				err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
								pfx, i);
			}
			if (err < 0)
				return err;
		}
+25 −22
Original line number Diff line number Diff line
@@ -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,14 +4319,12 @@ 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;
	}
}
}

static int stac92xx_init(struct hda_codec *codec)
{
@@ -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) {
	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);
		} else {
			stac_vrefout_set(codec,
					spec->gpio_led, spec->vref_led);
		}
	}
	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 @@ again:

#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 @@ again:

#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;
Loading