2 * TXx9 ACLC AC97 driver
4 * Copyright (C) 2009 Atsushi Nemoto
6 * Based on RBTX49xx patch from CELF patch archive.
7 * (C) Copyright TOSHIBA CORPORATION 2004-2006
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/delay.h>
17 #include <linux/interrupt.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/soc.h>
25 (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
28 SNDRV_PCM_RATE_8000_48000
31 #define AC97_FMTS SNDRV_PCM_FMTBIT_S16_BE
33 #define AC97_FMTS SNDRV_PCM_FMTBIT_S16_LE
36 static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq
);
38 /* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
39 static struct txx9aclc_soc_device
*txx9aclc_soc_dev
;
41 static int txx9aclc_regready(struct txx9aclc_soc_device
*dev
)
43 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
45 return __raw_readl(drvdata
->base
+ ACINTSTS
) & ACINT_REGACCRDY
;
48 /* AC97 controller reads codec register */
49 static unsigned short txx9aclc_ac97_read(struct snd_ac97
*ac97
,
52 struct txx9aclc_soc_device
*dev
= txx9aclc_soc_dev
;
53 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
54 void __iomem
*base
= drvdata
->base
;
57 if (!(__raw_readl(base
+ ACINTSTS
) & ACINT_CODECRDY(ac97
->num
)))
59 reg
|= ac97
->num
<< 7;
60 dat
= (reg
<< ACREGACC_REG_SHIFT
) | ACREGACC_READ
;
61 __raw_writel(dat
, base
+ ACREGACC
);
62 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTEN
);
63 if (!wait_event_timeout(ac97_waitq
, txx9aclc_regready(dev
), HZ
)) {
64 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTDIS
);
65 dev_err(dev
->soc_dev
.dev
, "ac97 read timeout (reg %#x)\n", reg
);
69 dat
= __raw_readl(base
+ ACREGACC
);
70 if (((dat
>> ACREGACC_REG_SHIFT
) & 0xff) != reg
) {
71 dev_err(dev
->soc_dev
.dev
, "reg mismatch %x with %x\n",
76 dat
= (dat
>> ACREGACC_DAT_SHIFT
) & 0xffff;
78 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTDIS
);
82 /* AC97 controller writes to codec register */
83 static void txx9aclc_ac97_write(struct snd_ac97
*ac97
, unsigned short reg
,
86 struct txx9aclc_soc_device
*dev
= txx9aclc_soc_dev
;
87 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
88 void __iomem
*base
= drvdata
->base
;
90 __raw_writel(((reg
| (ac97
->num
<< 7)) << ACREGACC_REG_SHIFT
) |
91 (val
<< ACREGACC_DAT_SHIFT
),
93 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTEN
);
94 if (!wait_event_timeout(ac97_waitq
, txx9aclc_regready(dev
), HZ
)) {
95 dev_err(dev
->soc_dev
.dev
,
96 "ac97 write timeout (reg %#x)\n", reg
);
98 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTDIS
);
101 static void txx9aclc_ac97_cold_reset(struct snd_ac97
*ac97
)
103 struct txx9aclc_soc_device
*dev
= txx9aclc_soc_dev
;
104 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
105 void __iomem
*base
= drvdata
->base
;
106 u32 ready
= ACINT_CODECRDY(ac97
->num
) | ACINT_REGACCRDY
;
108 __raw_writel(ACCTL_ENLINK
, base
+ ACCTLDIS
);
111 __raw_writel(ACCTL_ENLINK
, base
+ ACCTLEN
);
112 /* wait for primary codec ready status */
113 __raw_writel(ready
, base
+ ACINTEN
);
114 if (!wait_event_timeout(ac97_waitq
,
115 (__raw_readl(base
+ ACINTSTS
) & ready
) == ready
,
117 dev_err(&ac97
->dev
, "primary codec is not ready "
119 __raw_readl(base
+ ACINTSTS
));
121 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTSTS
);
122 __raw_writel(ready
, base
+ ACINTDIS
);
125 /* AC97 controller operations */
126 struct snd_ac97_bus_ops soc_ac97_ops
= {
127 .read
= txx9aclc_ac97_read
,
128 .write
= txx9aclc_ac97_write
,
129 .reset
= txx9aclc_ac97_cold_reset
,
131 EXPORT_SYMBOL_GPL(soc_ac97_ops
);
133 static irqreturn_t
txx9aclc_ac97_irq(int irq
, void *dev_id
)
135 struct txx9aclc_plat_drvdata
*drvdata
= dev_id
;
136 void __iomem
*base
= drvdata
->base
;
138 __raw_writel(__raw_readl(base
+ ACINTMSTS
), base
+ ACINTDIS
);
139 wake_up(&ac97_waitq
);
143 static int txx9aclc_ac97_probe(struct platform_device
*pdev
,
144 struct snd_soc_dai
*dai
)
146 struct snd_soc_device
*socdev
= platform_get_drvdata(pdev
);
147 struct txx9aclc_soc_device
*dev
=
148 container_of(socdev
, struct txx9aclc_soc_device
, soc_dev
);
150 dev
->aclc_pdev
= to_platform_device(dai
->dev
);
151 txx9aclc_soc_dev
= dev
;
155 static void txx9aclc_ac97_remove(struct platform_device
*pdev
,
156 struct snd_soc_dai
*dai
)
158 struct platform_device
*aclc_pdev
= to_platform_device(dai
->dev
);
159 struct txx9aclc_plat_drvdata
*drvdata
= platform_get_drvdata(aclc_pdev
);
161 /* disable AC-link */
162 __raw_writel(ACCTL_ENLINK
, drvdata
->base
+ ACCTLDIS
);
163 txx9aclc_soc_dev
= NULL
;
166 struct snd_soc_dai txx9aclc_ac97_dai
= {
167 .name
= "txx9aclc_ac97",
169 .probe
= txx9aclc_ac97_probe
,
170 .remove
= txx9aclc_ac97_remove
,
173 .formats
= AC97_FMTS
,
179 .formats
= AC97_FMTS
,
184 EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai
);
186 static int __devinit
txx9aclc_ac97_dev_probe(struct platform_device
*pdev
)
188 struct txx9aclc_plat_drvdata
*drvdata
;
193 irq
= platform_get_irq(pdev
, 0);
196 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
200 if (!devm_request_mem_region(&pdev
->dev
, r
->start
, resource_size(r
),
201 dev_name(&pdev
->dev
)))
204 drvdata
= devm_kzalloc(&pdev
->dev
, sizeof(*drvdata
), GFP_KERNEL
);
207 platform_set_drvdata(pdev
, drvdata
);
208 drvdata
->physbase
= r
->start
;
209 if (sizeof(drvdata
->physbase
) > sizeof(r
->start
) &&
210 r
->start
>= TXX9_DIRECTMAP_BASE
&&
211 r
->start
< TXX9_DIRECTMAP_BASE
+ 0x400000)
212 drvdata
->physbase
|= 0xf00000000ull
;
213 drvdata
->base
= devm_ioremap(&pdev
->dev
, r
->start
, resource_size(r
));
216 err
= devm_request_irq(&pdev
->dev
, irq
, txx9aclc_ac97_irq
,
217 IRQF_DISABLED
, dev_name(&pdev
->dev
), drvdata
);
221 txx9aclc_ac97_dai
.dev
= &pdev
->dev
;
222 return snd_soc_register_dai(&txx9aclc_ac97_dai
);
225 static int __devexit
txx9aclc_ac97_dev_remove(struct platform_device
*pdev
)
227 snd_soc_unregister_dai(&txx9aclc_ac97_dai
);
231 static struct platform_driver txx9aclc_ac97_driver
= {
232 .probe
= txx9aclc_ac97_dev_probe
,
233 .remove
= __devexit_p(txx9aclc_ac97_dev_remove
),
235 .name
= "txx9aclc-ac97",
236 .owner
= THIS_MODULE
,
240 static int __init
txx9aclc_ac97_init(void)
242 return platform_driver_register(&txx9aclc_ac97_driver
);
245 static void __exit
txx9aclc_ac97_exit(void)
247 platform_driver_unregister(&txx9aclc_ac97_driver
);
250 module_init(txx9aclc_ac97_init
);
251 module_exit(txx9aclc_ac97_exit
);
253 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
254 MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
255 MODULE_LICENSE("GPL");