Loading Documentation/devicetree/bindings/sound/ti,tas5086.txt +11 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,17 @@ Optional properties: When not specified, the hardware default of 1300ms is retained. - ti,mid-z-channel-X: Boolean properties, X being a number from 1 to 6. If given, channel X will start with the Mid-Z start sequence, otherwise the default Low-Z scheme is used. The correct configuration depends on how the power stages connected to the PWM output pins work. Not all power stages are compatible to Mid-Z - please refer to the datasheets for more details. Most systems should not set any of these properties. Examples: i2c_bus { Loading sound/soc/codecs/tas5086.c +326 −4 Original line number Diff line number Diff line Loading @@ -83,6 +83,14 @@ #define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */ #define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */ #define TAS5086_BKNDERR 0x1c #define TAS5086_INPUT_MUX 0x20 #define TAS5086_PWM_OUTPUT_MUX 0x25 #define TAS5086_MAX_REGISTER TAS5086_PWM_OUTPUT_MUX #define TAS5086_PWM_START_MIDZ_FOR_START_1 (1 << 7) #define TAS5086_PWM_START_MIDZ_FOR_START_2 (1 << 6) #define TAS5086_PWM_START_CHANNEL_MASK (0x3f) /* * Default TAS5086 power-up configuration Loading Loading @@ -119,9 +127,30 @@ static const struct reg_default tas5086_reg_defaults[] = { { 0x1c, 0x05 }, }; static int tas5086_register_size(struct device *dev, unsigned int reg) { switch (reg) { case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR: return 1; case TAS5086_INPUT_MUX: case TAS5086_PWM_OUTPUT_MUX: return 4; } dev_err(dev, "Unsupported register address: %d\n", reg); return 0; } static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) { return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); switch (reg) { case 0x0f: case 0x11 ... 0x17: case 0x1d ... 0x1f: return false; default: return true; } } static bool tas5086_volatile_reg(struct device *dev, unsigned int reg) Loading @@ -140,6 +169,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg) return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); } static int tas5086_reg_write(void *context, unsigned int reg, unsigned int value) { struct i2c_client *client = context; unsigned int i, size; uint8_t buf[5]; int ret; size = tas5086_register_size(&client->dev, reg); if (size == 0) return -EINVAL; buf[0] = reg; for (i = size; i >= 1; --i) { buf[i] = value; value >>= 8; } ret = i2c_master_send(client, buf, size + 1); if (ret == size + 1) return 0; else if (ret < 0) return ret; else return -EIO; } static int tas5086_reg_read(void *context, unsigned int reg, unsigned int *value) { struct i2c_client *client = context; uint8_t send_buf, recv_buf[4]; struct i2c_msg msgs[2]; unsigned int size; unsigned int i; int ret; size = tas5086_register_size(&client->dev, reg); if (size == 0) return -EINVAL; send_buf = reg; msgs[0].addr = client->addr; msgs[0].len = sizeof(send_buf); msgs[0].buf = &send_buf; msgs[0].flags = 0; msgs[1].addr = client->addr; msgs[1].len = size; msgs[1].buf = recv_buf; msgs[1].flags = I2C_M_RD; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (ret < 0) return ret; else if (ret != ARRAY_SIZE(msgs)) return -EIO; *value = 0; for (i = 0; i < size; i++) { *value <<= 8; *value |= recv_buf[i]; } return 0; } struct tas5086_private { struct regmap *regmap; unsigned int mclk, sclk; Loading Loading @@ -376,6 +475,202 @@ static const struct snd_kcontrol_new tas5086_controls[] = { tas5086_get_deemph, tas5086_put_deemph), }; /* Input mux controls */ static const char *tas5086_dapm_sdin_texts[] = { "SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R", "SDIN3-L", "SDIN3-R", "Ground (0)", "nc" }; static const struct soc_enum tas5086_dapm_input_mux_enum[] = { SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0, 8, tas5086_dapm_sdin_texts), }; static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = { SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]), SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]), SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]), SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]), SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]), SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]), }; /* Output mux controls */ static const char *tas5086_dapm_channel_texts[] = { "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux", "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" }; static const struct soc_enum tas5086_dapm_output_mux_enum[] = { SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0, 6, tas5086_dapm_channel_texts), }; static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = { SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]), SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]), SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]), SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]), SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]), SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]), }; static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = { SND_SOC_DAPM_INPUT("SDIN1-L"), SND_SOC_DAPM_INPUT("SDIN1-R"), SND_SOC_DAPM_INPUT("SDIN2-L"), SND_SOC_DAPM_INPUT("SDIN2-R"), SND_SOC_DAPM_INPUT("SDIN3-L"), SND_SOC_DAPM_INPUT("SDIN3-R"), SND_SOC_DAPM_INPUT("SDIN4-L"), SND_SOC_DAPM_INPUT("SDIN4-R"), SND_SOC_DAPM_OUTPUT("PWM1"), SND_SOC_DAPM_OUTPUT("PWM2"), SND_SOC_DAPM_OUTPUT("PWM3"), SND_SOC_DAPM_OUTPUT("PWM4"), SND_SOC_DAPM_OUTPUT("PWM5"), SND_SOC_DAPM_OUTPUT("PWM6"), SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[0]), SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[1]), SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[2]), SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[3]), SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[4]), SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[5]), SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[0]), SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[1]), SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[2]), SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[3]), SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[4]), SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[5]), }; static const struct snd_soc_dapm_route tas5086_dapm_routes[] = { /* SDIN inputs -> channel muxes */ { "Channel 1 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 1 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 1 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 1 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 1 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 1 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 3 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 3 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 3 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 3 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 3 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 3 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 4 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 4 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 4 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 4 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 4 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 4 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 5 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 5 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 5 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 5 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 5 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 5 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 6 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 6 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 6 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 6 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 6 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 6 Mux", "SDIN3-R", "SDIN3-R" }, /* Channel muxes -> PWM muxes */ { "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" }, /* The PWM muxes are directly connected to the PWM outputs */ { "PWM1", NULL, "PWM1 Mux" }, { "PWM2", NULL, "PWM2 Mux" }, { "PWM3", NULL, "PWM3 Mux" }, { "PWM4", NULL, "PWM4 Mux" }, { "PWM5", NULL, "PWM5 Mux" }, { "PWM6", NULL, "PWM6 Mux" }, }; static const struct snd_soc_dai_ops tas5086_dai_ops = { .hw_params = tas5086_hw_params, .set_sysclk = tas5086_set_dai_sysclk, Loading Loading @@ -426,12 +721,33 @@ static int tas5086_probe(struct snd_soc_codec *codec) { struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int charge_period = 1300000; /* hardware default is 1300 ms */ u8 pwm_start_mid_z = 0; int i, ret; if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { struct device_node *of_node = codec->dev->of_node; of_property_read_u32(of_node, "ti,charge-period", &charge_period); for (i = 0; i < 6; i++) { char name[25]; snprintf(name, sizeof(name), "ti,mid-z-channel-%d", i + 1); if (of_get_property(of_node, name, NULL) != NULL) pwm_start_mid_z |= 1 << i; } } /* * If any of the channels is configured to start in Mid-Z mode, * configure 'part 1' of the PWM starts to use Mid-Z, and tell * all configured mid-z channels to start start under 'part 1'. */ if (pwm_start_mid_z) regmap_write(priv->regmap, TAS5086_PWM_START, TAS5086_PWM_START_MIDZ_FOR_START_1 | pwm_start_mid_z); /* lookup and set split-capacitor charge period */ if (charge_period == 0) { Loading Loading @@ -490,6 +806,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { .resume = tas5086_soc_resume, .controls = tas5086_controls, .num_controls = ARRAY_SIZE(tas5086_controls), .dapm_widgets = tas5086_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tas5086_dapm_widgets), .dapm_routes = tas5086_dapm_routes, .num_dapm_routes = ARRAY_SIZE(tas5086_dapm_routes), }; static const struct i2c_device_id tas5086_i2c_id[] = { Loading @@ -500,14 +820,16 @@ MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id); static const struct regmap_config tas5086_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = ARRAY_SIZE(tas5086_reg_defaults), .val_bits = 32, .max_register = TAS5086_MAX_REGISTER, .reg_defaults = tas5086_reg_defaults, .num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults), .cache_type = REGCACHE_RBTREE, .volatile_reg = tas5086_volatile_reg, .writeable_reg = tas5086_writeable_reg, .readable_reg = tas5086_accessible_reg, .reg_read = tas5086_reg_read, .reg_write = tas5086_reg_write, }; static int tas5086_i2c_probe(struct i2c_client *i2c, Loading @@ -522,7 +844,7 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, if (!priv) return -ENOMEM; priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap); priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap); if (IS_ERR(priv->regmap)) { ret = PTR_ERR(priv->regmap); dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); Loading Loading
Documentation/devicetree/bindings/sound/ti,tas5086.txt +11 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,17 @@ Optional properties: When not specified, the hardware default of 1300ms is retained. - ti,mid-z-channel-X: Boolean properties, X being a number from 1 to 6. If given, channel X will start with the Mid-Z start sequence, otherwise the default Low-Z scheme is used. The correct configuration depends on how the power stages connected to the PWM output pins work. Not all power stages are compatible to Mid-Z - please refer to the datasheets for more details. Most systems should not set any of these properties. Examples: i2c_bus { Loading
sound/soc/codecs/tas5086.c +326 −4 Original line number Diff line number Diff line Loading @@ -83,6 +83,14 @@ #define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */ #define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */ #define TAS5086_BKNDERR 0x1c #define TAS5086_INPUT_MUX 0x20 #define TAS5086_PWM_OUTPUT_MUX 0x25 #define TAS5086_MAX_REGISTER TAS5086_PWM_OUTPUT_MUX #define TAS5086_PWM_START_MIDZ_FOR_START_1 (1 << 7) #define TAS5086_PWM_START_MIDZ_FOR_START_2 (1 << 6) #define TAS5086_PWM_START_CHANNEL_MASK (0x3f) /* * Default TAS5086 power-up configuration Loading Loading @@ -119,9 +127,30 @@ static const struct reg_default tas5086_reg_defaults[] = { { 0x1c, 0x05 }, }; static int tas5086_register_size(struct device *dev, unsigned int reg) { switch (reg) { case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR: return 1; case TAS5086_INPUT_MUX: case TAS5086_PWM_OUTPUT_MUX: return 4; } dev_err(dev, "Unsupported register address: %d\n", reg); return 0; } static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) { return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); switch (reg) { case 0x0f: case 0x11 ... 0x17: case 0x1d ... 0x1f: return false; default: return true; } } static bool tas5086_volatile_reg(struct device *dev, unsigned int reg) Loading @@ -140,6 +169,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg) return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); } static int tas5086_reg_write(void *context, unsigned int reg, unsigned int value) { struct i2c_client *client = context; unsigned int i, size; uint8_t buf[5]; int ret; size = tas5086_register_size(&client->dev, reg); if (size == 0) return -EINVAL; buf[0] = reg; for (i = size; i >= 1; --i) { buf[i] = value; value >>= 8; } ret = i2c_master_send(client, buf, size + 1); if (ret == size + 1) return 0; else if (ret < 0) return ret; else return -EIO; } static int tas5086_reg_read(void *context, unsigned int reg, unsigned int *value) { struct i2c_client *client = context; uint8_t send_buf, recv_buf[4]; struct i2c_msg msgs[2]; unsigned int size; unsigned int i; int ret; size = tas5086_register_size(&client->dev, reg); if (size == 0) return -EINVAL; send_buf = reg; msgs[0].addr = client->addr; msgs[0].len = sizeof(send_buf); msgs[0].buf = &send_buf; msgs[0].flags = 0; msgs[1].addr = client->addr; msgs[1].len = size; msgs[1].buf = recv_buf; msgs[1].flags = I2C_M_RD; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (ret < 0) return ret; else if (ret != ARRAY_SIZE(msgs)) return -EIO; *value = 0; for (i = 0; i < size; i++) { *value <<= 8; *value |= recv_buf[i]; } return 0; } struct tas5086_private { struct regmap *regmap; unsigned int mclk, sclk; Loading Loading @@ -376,6 +475,202 @@ static const struct snd_kcontrol_new tas5086_controls[] = { tas5086_get_deemph, tas5086_put_deemph), }; /* Input mux controls */ static const char *tas5086_dapm_sdin_texts[] = { "SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R", "SDIN3-L", "SDIN3-R", "Ground (0)", "nc" }; static const struct soc_enum tas5086_dapm_input_mux_enum[] = { SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4, 8, tas5086_dapm_sdin_texts), SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0, 8, tas5086_dapm_sdin_texts), }; static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = { SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]), SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]), SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]), SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]), SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]), SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]), }; /* Output mux controls */ static const char *tas5086_dapm_channel_texts[] = { "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux", "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" }; static const struct soc_enum tas5086_dapm_output_mux_enum[] = { SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4, 6, tas5086_dapm_channel_texts), SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0, 6, tas5086_dapm_channel_texts), }; static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = { SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]), SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]), SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]), SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]), SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]), SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]), }; static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = { SND_SOC_DAPM_INPUT("SDIN1-L"), SND_SOC_DAPM_INPUT("SDIN1-R"), SND_SOC_DAPM_INPUT("SDIN2-L"), SND_SOC_DAPM_INPUT("SDIN2-R"), SND_SOC_DAPM_INPUT("SDIN3-L"), SND_SOC_DAPM_INPUT("SDIN3-R"), SND_SOC_DAPM_INPUT("SDIN4-L"), SND_SOC_DAPM_INPUT("SDIN4-R"), SND_SOC_DAPM_OUTPUT("PWM1"), SND_SOC_DAPM_OUTPUT("PWM2"), SND_SOC_DAPM_OUTPUT("PWM3"), SND_SOC_DAPM_OUTPUT("PWM4"), SND_SOC_DAPM_OUTPUT("PWM5"), SND_SOC_DAPM_OUTPUT("PWM6"), SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[0]), SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[1]), SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[2]), SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[3]), SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[4]), SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_input_mux_controls[5]), SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[0]), SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[1]), SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[2]), SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[3]), SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[4]), SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0, &tas5086_dapm_output_mux_controls[5]), }; static const struct snd_soc_dapm_route tas5086_dapm_routes[] = { /* SDIN inputs -> channel muxes */ { "Channel 1 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 1 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 1 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 1 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 1 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 1 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 3 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 3 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 3 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 3 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 3 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 3 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 4 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 4 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 4 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 4 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 4 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 4 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 5 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 5 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 5 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 5 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 5 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 5 Mux", "SDIN3-R", "SDIN3-R" }, { "Channel 6 Mux", "SDIN1-L", "SDIN1-L" }, { "Channel 6 Mux", "SDIN1-R", "SDIN1-R" }, { "Channel 6 Mux", "SDIN2-L", "SDIN2-L" }, { "Channel 6 Mux", "SDIN2-R", "SDIN2-R" }, { "Channel 6 Mux", "SDIN3-L", "SDIN3-L" }, { "Channel 6 Mux", "SDIN3-R", "SDIN3-R" }, /* Channel muxes -> PWM muxes */ { "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" }, { "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" }, { "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" }, { "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" }, { "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" }, { "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" }, { "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" }, /* The PWM muxes are directly connected to the PWM outputs */ { "PWM1", NULL, "PWM1 Mux" }, { "PWM2", NULL, "PWM2 Mux" }, { "PWM3", NULL, "PWM3 Mux" }, { "PWM4", NULL, "PWM4 Mux" }, { "PWM5", NULL, "PWM5 Mux" }, { "PWM6", NULL, "PWM6 Mux" }, }; static const struct snd_soc_dai_ops tas5086_dai_ops = { .hw_params = tas5086_hw_params, .set_sysclk = tas5086_set_dai_sysclk, Loading Loading @@ -426,12 +721,33 @@ static int tas5086_probe(struct snd_soc_codec *codec) { struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int charge_period = 1300000; /* hardware default is 1300 ms */ u8 pwm_start_mid_z = 0; int i, ret; if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { struct device_node *of_node = codec->dev->of_node; of_property_read_u32(of_node, "ti,charge-period", &charge_period); for (i = 0; i < 6; i++) { char name[25]; snprintf(name, sizeof(name), "ti,mid-z-channel-%d", i + 1); if (of_get_property(of_node, name, NULL) != NULL) pwm_start_mid_z |= 1 << i; } } /* * If any of the channels is configured to start in Mid-Z mode, * configure 'part 1' of the PWM starts to use Mid-Z, and tell * all configured mid-z channels to start start under 'part 1'. */ if (pwm_start_mid_z) regmap_write(priv->regmap, TAS5086_PWM_START, TAS5086_PWM_START_MIDZ_FOR_START_1 | pwm_start_mid_z); /* lookup and set split-capacitor charge period */ if (charge_period == 0) { Loading Loading @@ -490,6 +806,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { .resume = tas5086_soc_resume, .controls = tas5086_controls, .num_controls = ARRAY_SIZE(tas5086_controls), .dapm_widgets = tas5086_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tas5086_dapm_widgets), .dapm_routes = tas5086_dapm_routes, .num_dapm_routes = ARRAY_SIZE(tas5086_dapm_routes), }; static const struct i2c_device_id tas5086_i2c_id[] = { Loading @@ -500,14 +820,16 @@ MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id); static const struct regmap_config tas5086_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = ARRAY_SIZE(tas5086_reg_defaults), .val_bits = 32, .max_register = TAS5086_MAX_REGISTER, .reg_defaults = tas5086_reg_defaults, .num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults), .cache_type = REGCACHE_RBTREE, .volatile_reg = tas5086_volatile_reg, .writeable_reg = tas5086_writeable_reg, .readable_reg = tas5086_accessible_reg, .reg_read = tas5086_reg_read, .reg_write = tas5086_reg_write, }; static int tas5086_i2c_probe(struct i2c_client *i2c, Loading @@ -522,7 +844,7 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, if (!priv) return -ENOMEM; priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap); priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap); if (IS_ERR(priv->regmap)) { ret = PTR_ERR(priv->regmap); dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); Loading