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