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 <linux/gfp.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/soc.h>
26 (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
29 SNDRV_PCM_RATE_8000_48000
32 #define AC97_FMTS SNDRV_PCM_FMTBIT_S16_BE
34 #define AC97_FMTS SNDRV_PCM_FMTBIT_S16_LE
37 static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq
);
39 /* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
40 static struct txx9aclc_soc_device
*txx9aclc_soc_dev
;
42 static int txx9aclc_regready(struct txx9aclc_soc_device
*dev
)
44 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
46 return __raw_readl(drvdata
->base
+ ACINTSTS
) & ACINT_REGACCRDY
;
49 /* AC97 controller reads codec register */
50 static unsigned short txx9aclc_ac97_read(struct snd_ac97
*ac97
,
53 struct txx9aclc_soc_device
*dev
= txx9aclc_soc_dev
;
54 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
55 void __iomem
*base
= drvdata
->base
;
58 if (!(__raw_readl(base
+ ACINTSTS
) & ACINT_CODECRDY(ac97
->num
)))
60 reg
|= ac97
->num
<< 7;
61 dat
= (reg
<< ACREGACC_REG_SHIFT
) | ACREGACC_READ
;
62 __raw_writel(dat
, base
+ ACREGACC
);
63 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTEN
);
64 if (!wait_event_timeout(ac97_waitq
, txx9aclc_regready(dev
), HZ
)) {
65 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTDIS
);
66 dev_err(dev
->soc_dev
.dev
, "ac97 read timeout (reg %#x)\n", reg
);
70 dat
= __raw_readl(base
+ ACREGACC
);
71 if (((dat
>> ACREGACC_REG_SHIFT
) & 0xff) != reg
) {
72 dev_err(dev
->soc_dev
.dev
, "reg mismatch %x with %x\n",
77 dat
= (dat
>> ACREGACC_DAT_SHIFT
) & 0xffff;
79 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTDIS
);
83 /* AC97 controller writes to codec register */
84 static void txx9aclc_ac97_write(struct snd_ac97
*ac97
, unsigned short reg
,
87 struct txx9aclc_soc_device
*dev
= txx9aclc_soc_dev
;
88 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
89 void __iomem
*base
= drvdata
->base
;
91 __raw_writel(((reg
| (ac97
->num
<< 7)) << ACREGACC_REG_SHIFT
) |
92 (val
<< ACREGACC_DAT_SHIFT
),
94 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTEN
);
95 if (!wait_event_timeout(ac97_waitq
, txx9aclc_regready(dev
), HZ
)) {
96 dev_err(dev
->soc_dev
.dev
,
97 "ac97 write timeout (reg %#x)\n", reg
);
99 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTDIS
);
102 static void txx9aclc_ac97_cold_reset(struct snd_ac97
*ac97
)
104 struct txx9aclc_soc_device
*dev
= txx9aclc_soc_dev
;
105 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_get_plat_drvdata(dev
);
106 void __iomem
*base
= drvdata
->base
;
107 u32 ready
= ACINT_CODECRDY(ac97
->num
) | ACINT_REGACCRDY
;
109 __raw_writel(ACCTL_ENLINK
, base
+ ACCTLDIS
);
112 __raw_writel(ACCTL_ENLINK
, base
+ ACCTLEN
);
113 /* wait for primary codec ready status */
114 __raw_writel(ready
, base
+ ACINTEN
);
115 if (!wait_event_timeout(ac97_waitq
,
116 (__raw_readl(base
+ ACINTSTS
) & ready
) == ready
,
118 dev_err(&ac97
->dev
, "primary codec is not ready "
120 __raw_readl(base
+ ACINTSTS
));
122 __raw_writel(ACINT_REGACCRDY
, base
+ ACINTSTS
);
123 __raw_writel(ready
, base
+ ACINTDIS
);
126 /* AC97 controller operations */
127 struct snd_ac97_bus_ops soc_ac97_ops
= {
128 .read
= txx9aclc_ac97_read
,
129 .write
= txx9aclc_ac97_write
,
130 .reset
= txx9aclc_ac97_cold_reset
,
132 EXPORT_SYMBOL_GPL(soc_ac97_ops
);
134 static irqreturn_t
txx9aclc_ac97_irq(int irq
, void *dev_id
)
136 struct txx9aclc_plat_drvdata
*drvdata
= dev_id
;
137 void __iomem
*base
= drvdata
->base
;
139 __raw_writel(__raw_readl(base
+ ACINTMSTS
), base
+ ACINTDIS
);
140 wake_up(&ac97_waitq
);
144 static int txx9aclc_ac97_probe(struct platform_device
*pdev
,
145 struct snd_soc_dai
*dai
)
147 struct snd_soc_device
*socdev
= platform_get_drvdata(pdev
);
148 struct txx9aclc_soc_device
*dev
=
149 container_of(socdev
, struct txx9aclc_soc_device
, soc_dev
);
151 dev
->aclc_pdev
= to_platform_device(dai
->dev
);
152 txx9aclc_soc_dev
= dev
;
156 static void txx9aclc_ac97_remove(struct platform_device
*pdev
,
157 struct snd_soc_dai
*dai
)
159 struct platform_device
*aclc_pdev
= to_platform_device(dai
->dev
);
160 struct txx9aclc_plat_drvdata
*drvdata
= platform_get_drvdata(aclc_pdev
);
162 /* disable AC-link */
163 __raw_writel(ACCTL_ENLINK
, drvdata
->base
+ ACCTLDIS
);
164 txx9aclc_soc_dev
= NULL
;
167 struct snd_soc_dai txx9aclc_ac97_dai
= {
168 .name
= "txx9aclc_ac97",
170 .probe
= txx9aclc_ac97_probe
,
171 .remove
= txx9aclc_ac97_remove
,
174 .formats
= AC97_FMTS
,
180 .formats
= AC97_FMTS
,
185 EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai
);
187 static int __devinit
txx9aclc_ac97_dev_probe(struct platform_device
*pdev
)
189 struct txx9aclc_plat_drvdata
*drvdata
;
194 irq
= platform_get_irq(pdev
, 0);
197 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
201 if (!devm_request_mem_region(&pdev
->dev
, r
->start
, resource_size(r
),
202 dev_name(&pdev
->dev
)))
205 drvdata
= devm_kzalloc(&pdev
->dev
, sizeof(*drvdata
), GFP_KERNEL
);
208 platform_set_drvdata(pdev
, drvdata
);
209 drvdata
->physbase
= r
->start
;
210 if (sizeof(drvdata
->physbase
) > sizeof(r
->start
) &&
211 r
->start
>= TXX9_DIRECTMAP_BASE
&&
212 r
->start
< TXX9_DIRECTMAP_BASE
+ 0x400000)
213 drvdata
->physbase
|= 0xf00000000ull
;
214 drvdata
->base
= devm_ioremap(&pdev
->dev
, r
->start
, resource_size(r
));
217 err
= devm_request_irq(&pdev
->dev
, irq
, txx9aclc_ac97_irq
,
218 IRQF_DISABLED
, dev_name(&pdev
->dev
), drvdata
);
222 txx9aclc_ac97_dai
.dev
= &pdev
->dev
;
223 return snd_soc_register_dai(&txx9aclc_ac97_dai
);
226 static int __devexit
txx9aclc_ac97_dev_remove(struct platform_device
*pdev
)
228 snd_soc_unregister_dai(&txx9aclc_ac97_dai
);
232 static struct platform_driver txx9aclc_ac97_driver
= {
233 .probe
= txx9aclc_ac97_dev_probe
,
234 .remove
= __devexit_p(txx9aclc_ac97_dev_remove
),
236 .name
= "txx9aclc-ac97",
237 .owner
= THIS_MODULE
,
241 static int __init
txx9aclc_ac97_init(void)
243 return platform_driver_register(&txx9aclc_ac97_driver
);
246 static void __exit
txx9aclc_ac97_exit(void)
248 platform_driver_unregister(&txx9aclc_ac97_driver
);
251 module_init(txx9aclc_ac97_init
);
252 module_exit(txx9aclc_ac97_exit
);
254 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
255 MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
256 MODULE_LICENSE("GPL");
257 MODULE_ALIAS("platform:txx9aclc-ac97");