aboutsummaryrefslogtreecommitdiff
path: root/sound/spi/at73c213.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/spi/at73c213.c')
-rw-r--r--sound/spi/at73c213.c103
1 files changed, 50 insertions, 53 deletions
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 89d6e9c3514..39522367897 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -69,7 +69,6 @@ struct snd_at73c213 {
int irq;
int period;
unsigned long bitrate;
- struct clk *bitclk;
struct ssc_device *ssc;
struct spi_device *spi;
u8 spi_wbuffer[2];
@@ -118,7 +117,7 @@ static struct snd_pcm_hardware snd_at73c213_playback_hw = {
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 8000, /* Replaced by chip->bitrate later. */
.rate_max = 50000, /* Replaced by chip->bitrate later. */
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 64 * 1024 - 1,
.period_bytes_min = 512,
@@ -133,7 +132,8 @@ static struct snd_pcm_hardware snd_at73c213_playback_hw = {
static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
{
unsigned long ssc_rate = clk_get_rate(chip->ssc->clk);
- unsigned long dac_rate_new, ssc_div, status;
+ unsigned long dac_rate_new, ssc_div;
+ int status;
unsigned long ssc_div_max, ssc_div_min;
int max_tries;
@@ -155,7 +155,7 @@ static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
if (max_tries < 1)
max_tries = 1;
- /* ssc_div must be a power of 2. */
+ /* ssc_div must be even. */
ssc_div = (ssc_div + 1) & ~1UL;
if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) {
@@ -174,7 +174,7 @@ static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
dac_rate_new = 8 * (ssc_rate / ssc_div);
status = clk_round_rate(chip->board->dac_clk, dac_rate_new);
- if (status < 0)
+ if (status <= 0)
return status;
/* Ignore difference smaller than 256 Hz. */
@@ -209,7 +209,13 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+ /* ensure buffer_size is a multiple of period_size */
+ err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ return err;
snd_at73c213_playback_hw.rate_min = chip->bitrate;
snd_at73c213_playback_hw.rate_max = chip->bitrate;
runtime->hw = snd_at73c213_playback_hw;
@@ -228,6 +234,14 @@ static int snd_at73c213_pcm_close(struct snd_pcm_substream *substream)
static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
+ struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+ int channels = params_channels(hw_params);
+ int val;
+
+ val = ssc_readl(chip->ssc->regs, TFMR);
+ val = SSC_BFINS(TFMR_DATNB, channels - 1, val);
+ ssc_writel(chip->ssc->regs, TFMR, val);
+
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
}
@@ -249,10 +263,12 @@ static int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream)
ssc_writel(chip->ssc->regs, PDC_TPR,
(long)runtime->dma_addr);
- ssc_writel(chip->ssc->regs, PDC_TCR, runtime->period_size * 2);
+ ssc_writel(chip->ssc->regs, PDC_TCR,
+ runtime->period_size * runtime->channels);
ssc_writel(chip->ssc->regs, PDC_TNPR,
(long)runtime->dma_addr + block_size);
- ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
+ ssc_writel(chip->ssc->regs, PDC_TNCR,
+ runtime->period_size * runtime->channels);
return 0;
}
@@ -314,16 +330,7 @@ static struct snd_pcm_ops at73c213_playback_ops = {
.pointer = snd_at73c213_pcm_pointer,
};
-static void snd_at73c213_pcm_free(struct snd_pcm *pcm)
-{
- struct snd_at73c213 *chip = snd_pcm_chip(pcm);
- if (chip->pcm) {
- snd_pcm_lib_preallocate_free_for_all(chip->pcm);
- chip->pcm = NULL;
- }
-}
-
-static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
+static int snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
{
struct snd_pcm *pcm;
int retval;
@@ -334,7 +341,6 @@ static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
goto out;
pcm->private_data = chip;
- pcm->private_free = snd_at73c213_pcm_free;
pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER;
strcpy(pcm->name, "at73c213");
chip->pcm = pcm;
@@ -375,7 +381,8 @@ static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id)
ssc_writel(chip->ssc->regs, PDC_TNPR,
(long)runtime->dma_addr + offset);
- ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
+ ssc_writel(chip->ssc->regs, PDC_TNCR,
+ runtime->period_size * runtime->channels);
retval = IRQ_HANDLED;
}
@@ -658,7 +665,7 @@ static int snd_at73c213_aux_capture_volume_info(
| (mask << 24) | (invert << 22)) \
}
-static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = {
+static struct snd_kcontrol_new snd_at73c213_controls[] = {
AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1),
AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1),
AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1),
@@ -702,7 +709,7 @@ AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN,
AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0),
};
-static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip)
+static int snd_at73c213_mixer(struct snd_at73c213 *chip)
{
struct snd_card *card;
int errval, idx;
@@ -872,8 +879,8 @@ static int snd_at73c213_dev_free(struct snd_device *device)
return 0;
}
-static int __devinit snd_at73c213_dev_init(struct snd_card *card,
- struct spi_device *spi)
+static int snd_at73c213_dev_init(struct snd_card *card,
+ struct spi_device *spi)
{
static struct snd_device_ops ops = {
.dev_free = snd_at73c213_dev_free,
@@ -920,8 +927,6 @@ static int __devinit snd_at73c213_dev_init(struct snd_card *card,
if (retval)
goto out_snd_dev;
- snd_card_set_dev(card, &spi->dev);
-
goto out;
out_snd_dev:
@@ -957,12 +962,11 @@ static int snd_at73c213_probe(struct spi_device *spi)
return PTR_ERR(board->dac_clk);
}
- retval = -ENOMEM;
-
/* Allocate "card" using some unused identifiers. */
snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);
- card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213));
- if (!card)
+ retval = snd_card_new(&spi->dev, -1, id, THIS_MODULE,
+ sizeof(struct snd_at73c213), &card);
+ if (retval < 0)
goto out;
chip = card->private_data;
@@ -1001,7 +1005,7 @@ out:
return retval;
}
-static int __devexit snd_at73c213_remove(struct spi_device *spi)
+static int snd_at73c213_remove(struct spi_device *spi)
{
struct snd_card *card = dev_get_drvdata(&spi->dev);
struct snd_at73c213 *chip = card->private_data;
@@ -1064,15 +1068,15 @@ out:
ssc_free(chip->ssc);
snd_card_free(card);
- dev_set_drvdata(&spi->dev, NULL);
return 0;
}
-#ifdef CONFIG_PM
-static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
+#ifdef CONFIG_PM_SLEEP
+
+static int snd_at73c213_suspend(struct device *dev)
{
- struct snd_card *card = dev_get_drvdata(&spi->dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct snd_at73c213 *chip = card->private_data;
ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));
@@ -1081,9 +1085,9 @@ static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
return 0;
}
-static int snd_at73c213_resume(struct spi_device *spi)
+static int snd_at73c213_resume(struct device *dev)
{
- struct snd_card *card = dev_get_drvdata(&spi->dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct snd_at73c213 *chip = card->private_data;
clk_enable(chip->board->dac_clk);
@@ -1091,33 +1095,26 @@ static int snd_at73c213_resume(struct spi_device *spi)
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend,
+ snd_at73c213_resume);
+#define AT73C213_PM_OPS (&at73c213_pm_ops)
+
#else
-#define snd_at73c213_suspend NULL
-#define snd_at73c213_resume NULL
+#define AT73C213_PM_OPS NULL
#endif
static struct spi_driver at73c213_driver = {
.driver = {
.name = "at73c213",
+ .pm = AT73C213_PM_OPS,
},
.probe = snd_at73c213_probe,
- .suspend = snd_at73c213_suspend,
- .resume = snd_at73c213_resume,
- .remove = __devexit_p(snd_at73c213_remove),
+ .remove = snd_at73c213_remove,
};
-static int __init at73c213_init(void)
-{
- return spi_register_driver(&at73c213_driver);
-}
-module_init(at73c213_init);
-
-static void __exit at73c213_exit(void)
-{
- spi_unregister_driver(&at73c213_driver);
-}
-module_exit(at73c213_exit);
+module_spi_driver(at73c213_driver);
-MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC");
MODULE_LICENSE("GPL");