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