]>
Commit | Line | Data |
---|---|---|
9cb2173e EG |
1 | /* |
2 | * STK1160 driver | |
3 | * | |
4 | * Copyright (C) 2012 Ezequiel Garcia | |
5 | * <elezegarcia--a.t--gmail.com> | |
6 | * | |
e36e6b5f MH |
7 | * Copyright (C) 2016 Marcel Hasler |
8 | * <mahasler--a.t--gmail.com> | |
9 | * | |
9cb2173e EG |
10 | * Based on Easycap driver by R.M. Thomas |
11 | * Copyright (C) 2010 R.M. Thomas | |
12 | * <rmthomas--a.t--sciolus.org> | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or | |
17 | * (at your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | */ | |
25 | ||
9a4825ed MH |
26 | #include <linux/delay.h> |
27 | ||
9cb2173e EG |
28 | #include "stk1160.h" |
29 | #include "stk1160-reg.h" | |
30 | ||
9a4825ed MH |
31 | static int stk1160_ac97_wait_transfer_complete(struct stk1160 *dev) |
32 | { | |
33 | unsigned long timeout = jiffies + msecs_to_jiffies(STK1160_AC97_TIMEOUT); | |
34 | u8 value; | |
35 | ||
36 | /* Wait for AC97 transfer to complete */ | |
37 | while (time_is_after_jiffies(timeout)) { | |
38 | stk1160_read_reg(dev, STK1160_AC97CTL_0, &value); | |
39 | ||
40 | if (!(value & (STK1160_AC97CTL_0_CR | STK1160_AC97CTL_0_CW))) | |
41 | return 0; | |
42 | ||
43 | usleep_range(50, 100); | |
44 | } | |
45 | ||
46 | stk1160_err("AC97 transfer took too long, this should never happen!"); | |
47 | return -EBUSY; | |
48 | } | |
49 | ||
e36e6b5f | 50 | static void stk1160_write_ac97(struct stk1160 *dev, u16 reg, u16 value) |
9cb2173e | 51 | { |
9cb2173e EG |
52 | /* Set codec register address */ |
53 | stk1160_write_reg(dev, STK1160_AC97_ADDR, reg); | |
54 | ||
55 | /* Set codec command */ | |
56 | stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff); | |
57 | stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8); | |
58 | ||
9a4825ed | 59 | /* Set command write bit to initiate write operation */ |
9cb2173e | 60 | stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c); |
9a4825ed MH |
61 | |
62 | /* Wait for command write bit to be cleared */ | |
63 | stk1160_ac97_wait_transfer_complete(dev); | |
9cb2173e EG |
64 | } |
65 | ||
e36e6b5f MH |
66 | #ifdef DEBUG |
67 | static u16 stk1160_read_ac97(struct stk1160 *dev, u16 reg) | |
9cb2173e | 68 | { |
9cb2173e EG |
69 | u8 vall = 0; |
70 | u8 valh = 0; | |
71 | ||
72 | /* Set codec register address */ | |
73 | stk1160_write_reg(dev, STK1160_AC97_ADDR, reg); | |
74 | ||
9a4825ed | 75 | /* Set command read bit to initiate read operation */ |
9cb2173e EG |
76 | stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b); |
77 | ||
9a4825ed MH |
78 | /* Wait for command read bit to be cleared */ |
79 | if (stk1160_ac97_wait_transfer_complete(dev) < 0) | |
80 | return 0; | |
81 | ||
82 | ||
9cb2173e EG |
83 | /* Retrieve register value */ |
84 | stk1160_read_reg(dev, STK1160_AC97_CMD, &vall); | |
85 | stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh); | |
86 | ||
87 | return (valh << 8) | vall; | |
88 | } | |
89 | ||
e36e6b5f | 90 | void stk1160_ac97_dump_regs(struct stk1160 *dev) |
9cb2173e | 91 | { |
e36e6b5f | 92 | u16 value; |
9cb2173e | 93 | |
e36e6b5f MH |
94 | value = stk1160_read_ac97(dev, 0x12); /* CD volume */ |
95 | stk1160_dbg("0x12 == 0x%04x", value); | |
9cb2173e | 96 | |
e36e6b5f MH |
97 | value = stk1160_read_ac97(dev, 0x10); /* Line-in volume */ |
98 | stk1160_dbg("0x10 == 0x%04x", value); | |
9cb2173e | 99 | |
e36e6b5f MH |
100 | value = stk1160_read_ac97(dev, 0x0e); /* MIC volume (mono) */ |
101 | stk1160_dbg("0x0e == 0x%04x", value); | |
9cb2173e | 102 | |
e36e6b5f MH |
103 | value = stk1160_read_ac97(dev, 0x16); /* Aux volume */ |
104 | stk1160_dbg("0x16 == 0x%04x", value); | |
105 | ||
106 | value = stk1160_read_ac97(dev, 0x1a); /* Record select */ | |
107 | stk1160_dbg("0x1a == 0x%04x", value); | |
108 | ||
109 | value = stk1160_read_ac97(dev, 0x02); /* Master volume */ | |
110 | stk1160_dbg("0x02 == 0x%04x", value); | |
111 | ||
112 | value = stk1160_read_ac97(dev, 0x1c); /* Record gain */ | |
113 | stk1160_dbg("0x1c == 0x%04x", value); | |
9cb2173e | 114 | } |
e36e6b5f | 115 | #endif |
9cb2173e | 116 | |
504fc028 | 117 | static int stk1160_has_audio(struct stk1160 *dev) |
1dc7df4d MH |
118 | { |
119 | u8 value; | |
120 | ||
121 | stk1160_read_reg(dev, STK1160_POSV_L, &value); | |
122 | return !(value & STK1160_POSV_L_ACDOUT); | |
123 | } | |
124 | ||
504fc028 | 125 | static int stk1160_has_ac97(struct stk1160 *dev) |
1dc7df4d MH |
126 | { |
127 | u8 value; | |
128 | ||
129 | stk1160_read_reg(dev, STK1160_POSV_L, &value); | |
130 | return !(value & STK1160_POSV_L_ACSYNC); | |
131 | } | |
132 | ||
e36e6b5f | 133 | void stk1160_ac97_setup(struct stk1160 *dev) |
9cb2173e | 134 | { |
1dc7df4d MH |
135 | if (!stk1160_has_audio(dev)) { |
136 | stk1160_info("Device doesn't support audio, skipping AC97 setup."); | |
137 | return; | |
138 | } | |
139 | ||
140 | if (!stk1160_has_ac97(dev)) { | |
141 | stk1160_info("Device uses internal 8-bit ADC, skipping AC97 setup."); | |
142 | return; | |
143 | } | |
144 | ||
e36e6b5f MH |
145 | /* Two-step reset AC97 interface and hardware codec */ |
146 | stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94); | |
147 | stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c); | |
9cb2173e | 148 | |
e36e6b5f MH |
149 | /* Set 16-bit audio data and choose L&R channel*/ |
150 | stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01); | |
151 | stk1160_write_reg(dev, STK1160_AC97CTL_1 + 3, 0x00); | |
152 | ||
153 | /* Setup channels */ | |
154 | stk1160_write_ac97(dev, 0x12, 0x8808); /* CD volume */ | |
155 | stk1160_write_ac97(dev, 0x10, 0x0808); /* Line-in volume */ | |
156 | stk1160_write_ac97(dev, 0x0e, 0x0008); /* MIC volume (mono) */ | |
157 | stk1160_write_ac97(dev, 0x16, 0x0808); /* Aux volume */ | |
158 | stk1160_write_ac97(dev, 0x1a, 0x0404); /* Record select */ | |
159 | stk1160_write_ac97(dev, 0x02, 0x0000); /* Master volume */ | |
160 | stk1160_write_ac97(dev, 0x1c, 0x0808); /* Record gain */ | |
161 | ||
162 | #ifdef DEBUG | |
163 | stk1160_ac97_dump_regs(dev); | |
164 | #endif | |
9cb2173e | 165 | } |