Commit be529a5b authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/tas5086' into asoc-next

parents 6c61bbf0 285d00c1
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -244,6 +245,8 @@ struct tas5086_private { ...@@ -244,6 +245,8 @@ struct tas5086_private {
unsigned int mclk, sclk; unsigned int mclk, sclk;
unsigned int format; unsigned int format;
bool deemph; bool deemph;
unsigned int charge_period;
unsigned int pwm_start_mid_z;
/* Current sample rate for de-emphasis control */ /* Current sample rate for de-emphasis control */
int rate; int rate;
/* GPIO driving Reset pin, if any */ /* GPIO driving Reset pin, if any */
...@@ -456,6 +459,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) ...@@ -456,6 +459,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
} }
static void tas5086_reset(struct tas5086_private *priv)
{
if (gpio_is_valid(priv->gpio_nreset)) {
/* Reset codec - minimum assertion time is 400ns */
gpio_direction_output(priv->gpio_nreset, 0);
udelay(1);
gpio_set_value(priv->gpio_nreset, 1);
/* Codec needs ~15ms to wake up */
msleep(15);
}
}
/* charge period values in microseconds */
static const int tas5086_charge_period[] = {
13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
};
static int tas5086_init(struct device *dev, struct tas5086_private *priv)
{
int ret, 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 (priv->pwm_start_mid_z)
regmap_write(priv->regmap, TAS5086_PWM_START,
TAS5086_PWM_START_MIDZ_FOR_START_1 |
priv->pwm_start_mid_z);
/* lookup and set split-capacitor charge period */
if (priv->charge_period == 0) {
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
} else {
i = index_in_array(tas5086_charge_period,
ARRAY_SIZE(tas5086_charge_period),
priv->charge_period);
if (i >= 0)
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
i + 0x08);
else
dev_warn(dev,
"Invalid split-cap charge period of %d ns.\n",
priv->charge_period);
}
/* enable factory trim */
ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
if (ret < 0)
return ret;
/* start all channels */
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
if (ret < 0)
return ret;
/* mute all channels for now */
ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
TAS5086_SOFT_MUTE_ALL);
if (ret < 0)
return ret;
return 0;
}
/* TAS5086 controls */ /* TAS5086 controls */
static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
...@@ -691,14 +763,39 @@ static struct snd_soc_dai_driver tas5086_dai = { ...@@ -691,14 +763,39 @@ static struct snd_soc_dai_driver tas5086_dai = {
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int tas5086_soc_suspend(struct snd_soc_codec *codec)
{
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
int ret;
/* Shut down all channels */
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60);
if (ret < 0)
return ret;
return 0;
}
static int tas5086_soc_resume(struct snd_soc_codec *codec) static int tas5086_soc_resume(struct snd_soc_codec *codec)
{ {
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
int ret;
tas5086_reset(priv);
regcache_mark_dirty(priv->regmap);
ret = tas5086_init(codec->dev, priv);
if (ret < 0)
return ret;
ret = regcache_sync(priv->regmap);
if (ret < 0)
return ret;
/* Restore codec state */ return 0;
return regcache_sync(priv->regmap);
} }
#else #else
#define tas5086_soc_suspend NULL
#define tas5086_soc_resume NULL #define tas5086_soc_resume NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
...@@ -710,23 +807,19 @@ static const struct of_device_id tas5086_dt_ids[] = { ...@@ -710,23 +807,19 @@ static const struct of_device_id tas5086_dt_ids[] = {
MODULE_DEVICE_TABLE(of, tas5086_dt_ids); MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
#endif #endif
/* charge period values in microseconds */
static const int tas5086_charge_period[] = {
13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
};
static int tas5086_probe(struct snd_soc_codec *codec) static int tas5086_probe(struct snd_soc_codec *codec)
{ {
struct tas5086_private *priv = snd_soc_codec_get_drvdata(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; int i, ret;
priv->pwm_start_mid_z = 0;
priv->charge_period = 1300000; /* hardware default is 1300 ms */
if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
struct device_node *of_node = codec->dev->of_node; struct device_node *of_node = codec->dev->of_node;
of_property_read_u32(of_node, "ti,charge-period", &charge_period);
of_property_read_u32(of_node, "ti,charge-period",
&priv->charge_period);
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
char name[25]; char name[25];
...@@ -735,43 +828,11 @@ static int tas5086_probe(struct snd_soc_codec *codec) ...@@ -735,43 +828,11 @@ static int tas5086_probe(struct snd_soc_codec *codec)
"ti,mid-z-channel-%d", i + 1); "ti,mid-z-channel-%d", i + 1);
if (of_get_property(of_node, name, NULL) != NULL) if (of_get_property(of_node, name, NULL) != NULL)
pwm_start_mid_z |= 1 << i; priv->pwm_start_mid_z |= 1 << i;
} }
} }
/* ret = tas5086_init(codec->dev, priv);
* 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) {
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
} else {
i = index_in_array(tas5086_charge_period,
ARRAY_SIZE(tas5086_charge_period),
charge_period);
if (i >= 0)
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
i + 0x08);
else
dev_warn(codec->dev,
"Invalid split-cap charge period of %d ns.\n",
charge_period);
}
/* enable factory trim */
ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
if (ret < 0)
return ret;
/* start all channels */
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -780,12 +841,6 @@ static int tas5086_probe(struct snd_soc_codec *codec) ...@@ -780,12 +841,6 @@ static int tas5086_probe(struct snd_soc_codec *codec)
if (ret < 0) if (ret < 0)
return ret; return ret;
/* mute all channels for now */
ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
TAS5086_SOFT_MUTE_ALL);
if (ret < 0)
return ret;
return 0; return 0;
} }
...@@ -803,6 +858,7 @@ static int tas5086_remove(struct snd_soc_codec *codec) ...@@ -803,6 +858,7 @@ static int tas5086_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
.probe = tas5086_probe, .probe = tas5086_probe,
.remove = tas5086_remove, .remove = tas5086_remove,
.suspend = tas5086_soc_suspend,
.resume = tas5086_soc_resume, .resume = tas5086_soc_resume,
.controls = tas5086_controls, .controls = tas5086_controls,
.num_controls = ARRAY_SIZE(tas5086_controls), .num_controls = ARRAY_SIZE(tas5086_controls),
...@@ -862,17 +918,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, ...@@ -862,17 +918,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
gpio_nreset = -EINVAL; gpio_nreset = -EINVAL;
if (gpio_is_valid(gpio_nreset)) {
/* Reset codec - minimum assertion time is 400ns */
gpio_direction_output(gpio_nreset, 0);
udelay(1);
gpio_set_value(gpio_nreset, 1);
/* Codec needs ~15ms to wake up */
msleep(15);
}
priv->gpio_nreset = gpio_nreset; priv->gpio_nreset = gpio_nreset;
tas5086_reset(priv);
/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment