diff options
Diffstat (limited to 'sound/soc/codecs/jz4740.c')
| -rw-r--r-- | sound/soc/codecs/jz4740.c | 197 | 
1 files changed, 77 insertions, 120 deletions
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 16253ec9b02..bcebd1a9ce3 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -15,6 +15,8 @@  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/slab.h> +#include <linux/io.h> +#include <linux/regmap.h>  #include <linux/delay.h> @@ -22,11 +24,11 @@  #include <sound/pcm.h>  #include <sound/pcm_params.h>  #include <sound/initval.h> -#include <sound/soc-dapm.h>  #include <sound/soc.h> +#include <sound/tlv.h>  #define JZ4740_REG_CODEC_1 0x0 -#define JZ4740_REG_CODEC_2 0x1 +#define JZ4740_REG_CODEC_2 0x4  #define JZ4740_CODEC_1_LINE_ENABLE BIT(29)  #define JZ4740_CODEC_1_MIC_ENABLE BIT(28) @@ -67,43 +69,36 @@  #define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET	 4  #define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET	 0 -static const uint32_t jz4740_codec_regs[] = { -	0x021b2302, 0x00170803, +static const struct reg_default jz4740_codec_reg_defaults[] = { +	{ JZ4740_REG_CODEC_1, 0x021b2302 }, +	{ JZ4740_REG_CODEC_2, 0x00170803 },  };  struct jz4740_codec { -	void __iomem *base; -	struct resource *mem; +	struct regmap *regmap;  }; -static unsigned int jz4740_codec_read(struct snd_soc_codec *codec, -	unsigned int reg) -{ -	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); -	return readl(jz4740_codec->base + (reg << 2)); -} - -static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg, -	unsigned int val) -{ -	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); -	u32 *cache = codec->reg_cache; +static const unsigned int jz4740_mic_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0, 2, TLV_DB_SCALE_ITEM(0, 600, 0), +	3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), +}; -	cache[reg] = val; -	writel(val, jz4740_codec->base + (reg << 2)); - -	return 0; -} +static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0); +static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0);  static const struct snd_kcontrol_new jz4740_codec_controls[] = { -	SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2, -			JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0), -	SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2, -			JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0), +	SOC_SINGLE_TLV("Master Playback Volume", JZ4740_REG_CODEC_2, +			JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0, +			jz4740_out_tlv), +	SOC_SINGLE_TLV("Master Capture Volume", JZ4740_REG_CODEC_2, +			JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0, +			jz4740_in_tlv),  	SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,  			JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1), -	SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2, -			JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0), +	SOC_SINGLE_TLV("Mic Capture Volume", JZ4740_REG_CODEC_2, +			JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0, +			jz4740_mic_tlv),  };  static const struct snd_kcontrol_new jz4740_codec_output_controls[] = { @@ -163,9 +158,8 @@ static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {  static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,  	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)  { +	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(dai->codec);  	uint32_t val; -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec =rtd->codec;  	switch (params_rate(params)) {  	case 8000: @@ -201,13 +195,13 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,  	val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET; -	snd_soc_update_bits(codec, JZ4740_REG_CODEC_2, +	regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_2,  				JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);  	return 0;  } -static struct snd_soc_dai_ops jz4740_codec_dai_ops = { +static const struct snd_soc_dai_ops jz4740_codec_dai_ops = {  	.hw_params = jz4740_codec_hw_params,  }; @@ -231,25 +225,23 @@ static struct snd_soc_dai_driver jz4740_codec_dai = {  	.symmetric_rates = 1,  }; -static void jz4740_codec_wakeup(struct snd_soc_codec *codec) +static void jz4740_codec_wakeup(struct regmap *regmap)  { -	int i; -	uint32_t *cache = codec->reg_cache; - -	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, +	regmap_update_bits(regmap, JZ4740_REG_CODEC_1,  		JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);  	udelay(2); -	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, +	regmap_update_bits(regmap, JZ4740_REG_CODEC_1,  		JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0); -	for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i) -		jz4740_codec_write(codec, i, cache[i]); +	regcache_sync(regmap);  }  static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,  	enum snd_soc_bias_level level)  { +	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); +	struct regmap *regmap = jz4740_codec->regmap;  	unsigned int mask;  	unsigned int value; @@ -262,12 +254,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,  				JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;  		value = 0; -		snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); +		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);  		break;  	case SND_SOC_BIAS_STANDBY:  		/* The only way to clear the suspend flag is to reset the codec */ -		if (codec->bias_level == SND_SOC_BIAS_OFF) -			jz4740_codec_wakeup(codec); +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) +			jz4740_codec_wakeup(regmap);  		mask = JZ4740_CODEC_1_VREF_DISABLE |  			JZ4740_CODEC_1_VREF_AMP_DISABLE | @@ -276,38 +268,30 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,  			JZ4740_CODEC_1_VREF_AMP_DISABLE |  			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; -		snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); +		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);  		break;  	case SND_SOC_BIAS_OFF:  		mask = JZ4740_CODEC_1_SUSPEND;  		value = JZ4740_CODEC_1_SUSPEND; -		snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); +		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); +		regcache_mark_dirty(regmap);  		break;  	default:  		break;  	} -	codec->bias_level = level; +	codec->dapm.bias_level = level;  	return 0;  }  static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)  { -	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, -			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); - -	snd_soc_add_controls(codec, jz4740_codec_controls, -		ARRAY_SIZE(jz4740_codec_controls)); - -	snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets, -		ARRAY_SIZE(jz4740_codec_dapm_widgets)); - -	snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes, -		ARRAY_SIZE(jz4740_codec_dapm_routes)); +	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); -	snd_soc_dapm_new_widgets(codec); +	regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1, +			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);  	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -323,7 +307,7 @@ static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)  #ifdef CONFIG_PM_SLEEP -static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state) +static int jz4740_codec_suspend(struct snd_soc_codec *codec)  {  	return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);  } @@ -343,103 +327,76 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {  	.remove = jz4740_codec_dev_remove,  	.suspend = jz4740_codec_suspend,  	.resume = jz4740_codec_resume, -	.read = jz4740_codec_read, -	.write = jz4740_codec_write,  	.set_bias_level = jz4740_codec_set_bias_level, -	.reg_cache_default	= jz4740_codec_regs, -	.reg_word_size = sizeof(u32), -	.reg_cache_size	= 2, + +	.controls = jz4740_codec_controls, +	.num_controls = ARRAY_SIZE(jz4740_codec_controls), +	.dapm_widgets = jz4740_codec_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets), +	.dapm_routes = jz4740_codec_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),  }; -static int __devinit jz4740_codec_probe(struct platform_device *pdev) +static const struct regmap_config jz4740_codec_regmap_config = { +	.reg_bits = 32, +	.reg_stride = 4, +	.val_bits = 32, +	.max_register = JZ4740_REG_CODEC_2, + +	.reg_defaults = jz4740_codec_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +}; + +static int jz4740_codec_probe(struct platform_device *pdev)  {  	int ret;  	struct jz4740_codec *jz4740_codec;  	struct resource *mem; +	void __iomem *base; -	jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL); +	jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec), +				    GFP_KERNEL);  	if (!jz4740_codec)  		return -ENOMEM;  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!mem) { -		dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); -		ret = -ENOENT; -		goto err_free_codec; -	} +	base = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(base)) +		return PTR_ERR(base); -	mem = request_mem_region(mem->start, resource_size(mem), pdev->name); -	if (!mem) { -		dev_err(&pdev->dev, "Failed to request mmio memory region\n"); -		ret = -EBUSY; -		goto err_free_codec; -	} - -	jz4740_codec->base = ioremap(mem->start, resource_size(mem)); -	if (!jz4740_codec->base) { -		dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); -		ret = -EBUSY; -		goto err_release_mem_region; -	} -	jz4740_codec->mem = mem; +	jz4740_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base, +					    &jz4740_codec_regmap_config); +	if (IS_ERR(jz4740_codec->regmap)) +		return PTR_ERR(jz4740_codec->regmap);  	platform_set_drvdata(pdev, jz4740_codec);  	ret = snd_soc_register_codec(&pdev->dev,  			&soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1); -	if (ret) { +	if (ret)  		dev_err(&pdev->dev, "Failed to register codec\n"); -		goto err_iounmap; -	} - -	return 0; - -err_iounmap: -	iounmap(jz4740_codec->base); -err_release_mem_region: -	release_mem_region(mem->start, resource_size(mem)); -err_free_codec: -	kfree(jz4740_codec);  	return ret;  } -static int __devexit jz4740_codec_remove(struct platform_device *pdev) +static int jz4740_codec_remove(struct platform_device *pdev)  { -	struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev); -	struct resource *mem = jz4740_codec->mem; -  	snd_soc_unregister_codec(&pdev->dev); -	iounmap(jz4740_codec->base); -	release_mem_region(mem->start, resource_size(mem)); - -	platform_set_drvdata(pdev, NULL); -	kfree(jz4740_codec); -  	return 0;  }  static struct platform_driver jz4740_codec_driver = {  	.probe = jz4740_codec_probe, -	.remove = __devexit_p(jz4740_codec_remove), +	.remove = jz4740_codec_remove,  	.driver = {  		.name = "jz4740-codec",  		.owner = THIS_MODULE,  	},  }; -static int __init jz4740_codec_init(void) -{ -	return platform_driver_register(&jz4740_codec_driver); -} -module_init(jz4740_codec_init); - -static void __exit jz4740_codec_exit(void) -{ -	platform_driver_unregister(&jz4740_codec_driver); -} -module_exit(jz4740_codec_exit); +module_platform_driver(jz4740_codec_driver);  MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");  MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");  | 
