hh.org updates
[hh.org.git] / arch / arm / mach-pxa / aximx5 / aximx5_ac97.c
blobba75f5a630f7c05aa161b223fe2451fa0a407cb0
1 /*
2 * AC97 controller handler for Dell Axim X5.
3 * Handles touchscreen, battery and sound.
5 * Copyright © 2004 Andrew Zabolotny <zap@homelink.ru>
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/device.h>
15 #include <linux/soc-old.h>
16 #include <linux/delay.h>
17 #include <linux/battery.h>
18 #include <asm/irq.h>
19 #include <asm/hardware.h>
20 #include <asm/arch/pxa-regs.h>
21 #include <asm/arch/aximx5-gpio.h>
23 #include "../sound/oss/wm97xx.h"
24 #include "../drivers/soc/mq11xx.h"
26 static wm97xx_public *tspub;
27 extern int driver_pxa_ac97_wm97xx;
28 static struct mediaq11xx_base *mq_base;
30 /* Time interval in jiffies at which BMON and AUX inputs are sampled.
32 #define BMON_AUX_SAMPLE_INTERVAL (10*HZ)
34 /*----------------------------------------------* Battery monitor *----------*/
36 /* Discharge curve for main battery (11 points) */
37 static u16 main_charge [] =
38 { 1432, 1448, 1463, 1470, 1479, 1490, 1516, 1537, 1558, 1589, 1619, 1684, 4096 };
40 /* Discharge curve for backup battery (11 points) */
41 static u16 backup_charge [] =
42 { 3252, 3277, 3287, 3298, 3308, 3337, 3360, 3382, 3402, 3428, 3455, 3486, 4096 };
44 /* Compute the percentage of remaining charge given current
45 * voltage reading and the discharge curve.
46 * Returns a value in the range 0-65536 (100%) or -1 on error.
48 static int compute_charge (int val, u16 *dc)
50 int i = 0;
52 if (val < dc [0] / 2)
53 return -1;
54 if (val < dc [0])
55 return 0;
57 while (i < 11 && val >= dc [i + 1])
58 i++;
60 if (i >= 11)
61 return 0x10000;
63 return (i * 5958) + (5958 * (val - dc [i])) / (dc [i + 1] - dc [i]);
66 static int aximx5_m_get_max_charge (struct battery *bat)
68 return mq_base->get_GPIO (mq_base, 66) ? 1400 : 3400;
71 static int aximx5_m_get_min_charge (struct battery *bat)
73 return 0;
76 static int aximx5_m_get_charge (struct battery *bat)
78 int bmon = tspub->get_auxconv (tspub, WM97XX_AC_BMON);
79 return (compute_charge (bmon, main_charge) *
80 aximx5_m_get_max_charge (bat)) >> 16;
83 static int aximx5_m_get_max_voltage (struct battery *bat)
85 return 3700;
88 static int aximx5_m_get_min_voltage (struct battery *bat)
90 return 3100;
93 static int aximx5_m_get_voltage (struct battery *bat)
95 int bmon = tspub->get_auxconv (tspub, WM97XX_AC_BMON);
96 if (bmon < 0)
97 return bmon;
99 /* My guess is that a 3V reference voltage is connected to the WM9705
100 * AVDD input (see WM9705 datasheet) (perhaps the backup battery).
101 * Compute the real battery voltage given the fact that it is divided
102 * by three by the internal 10k-20k divider, and the fact that
103 * 3000mV == 4096 (in ADC coordinate system).
106 return (3 * 3000 * bmon) >> 12;
109 static int aximx5_m_get_status (struct battery *bat)
111 return GET_AXIMX5_GPIO (CHARGING) ? BATTERY_STATUS_CHARGING :
112 GET_AXIMX5_GPIO (AC_POWER_N) ? BATTERY_STATUS_DISCHARGING :
113 BATTERY_STATUS_NOT_CHARGING;
116 static struct battery aximx5_main_battery = {
117 .name = "main",
118 //.id
119 //.type
120 .get_max_voltage = &aximx5_m_get_max_voltage,
121 .get_min_voltage = &aximx5_m_get_min_voltage,
122 .get_voltage = &aximx5_m_get_voltage,
123 .get_max_charge = &aximx5_m_get_max_charge,
124 .get_min_charge = &aximx5_m_get_min_charge,
125 .get_charge = &aximx5_m_get_charge,
126 .get_status = &aximx5_m_get_status
129 static int aximx5_b_get_max_charge (struct battery *bat)
131 /* Most CR3032 batteries have approximatively 200mAh capacity.
133 return 200;
136 static int aximx5_b_get_min_charge (struct battery *bat)
138 return 0;
141 static int aximx5_b_get_charge (struct battery *bat)
143 int aux = tspub->get_auxconv (tspub, WM97XX_AC_AUX1);
144 return (compute_charge (aux, backup_charge) *
145 aximx5_b_get_max_charge (bat)) >> 16;
148 static int aximx5_b_get_max_voltage (struct battery *bat)
150 return 3000;
153 static int aximx5_b_get_min_voltage (struct battery *bat)
155 return 2700;
158 static int aximx5_b_get_voltage (struct battery *bat)
160 int aux = tspub->get_auxconv (tspub, WM97XX_AC_AUX1);
161 if (aux < 0)
162 return aux;
164 /* When the battery voltage is 3.00V, the AUX ADC shows
165 * a value of 3518. So I found the coefficient for the
166 * reverse translation: (3000 * 4096) / 3518 = 3493
169 return (aux * 3493) >> 12;
172 static int aximx5_b_get_status (struct battery *bat)
174 return BATTERY_STATUS_NOT_CHARGING;
177 static struct battery aximx5_backup_battery = {
178 .name = "backup",
179 //.id
180 //.type
181 .get_max_voltage = &aximx5_b_get_max_voltage,
182 .get_min_voltage = &aximx5_b_get_min_voltage,
183 .get_voltage = &aximx5_b_get_voltage,
184 .get_max_charge = &aximx5_b_get_max_charge,
185 .get_min_charge = &aximx5_b_get_min_charge,
186 .get_charge = &aximx5_b_get_charge,
187 .get_status = &aximx5_b_get_status
190 void wm97xx_prepare_aux (wm97xx_public *wmpub, wm97xx_aux_conv ac, int stage)
192 /* Enable a 3.3k load resistor on the backup battery,
193 * otherwise the voltage measurements won't be precise.
195 mq_base->set_GPIO (mq_base, 61, stage ?
196 (MQ_GPIO_IN | MQ_GPIO_OUT0) :
197 (MQ_GPIO_IN | MQ_GPIO_OUT1));
198 /* Wait 1ms for battery voltage to stabilize */
199 if (stage == 0)
200 udelay (1000);
203 /*----------------------------------------------* Amplifier power *----------*/
205 /* Update the Axim-specific GPIOs so that power amplifier is enabled/disabled
206 * as appropiate.
208 static int aximx5_amplifier (struct ac97_codec *codec, int on)
210 static int power_on = 0;
212 if (on)
213 on = 1;
214 if (power_on != on) {
215 mq_base->set_power (mq_base, MEDIAQ_11XX_SPI_DEVICE_ID, on);
216 power_on = on;
219 /* GPIO24 seems to be amplifier power, GPIO23 amplifier mute.
220 * When the sound is disabled, we disable GPIO23 first; when
221 * the sound is enabled, we do it vice versa. This avoids
222 * loud clicks in the speaker.
224 set_task_state (current, TASK_INTERRUPTIBLE);
225 if (on) {
226 mq_base->set_GPIO (mq_base, 24, MQ_GPIO_OUT1);
227 schedule_timeout(HZ/4);
228 mq_base->set_GPIO (mq_base, 23, MQ_GPIO_OUT1);
229 } else {
230 mq_base->set_GPIO (mq_base, 23, MQ_GPIO_OUT0);
231 schedule_timeout(HZ/4);
232 mq_base->set_GPIO (mq_base, 24, MQ_GPIO_OUT0);
235 return 0;
238 static int __init
239 aximx5_ac97_init(void)
241 wm97xx_params params;
242 int mixer;
244 /* Pull in the DMA touchscreen driver */
245 //driver_pxa_ac97_wm97xx = 1;
247 tspub = wm97xx_get_device (0);
248 if (unlikely (!tspub)) {
249 printk (KERN_INFO "The WM9705 chip has not been initialized\n");
250 return -ENODEV;
253 /* Retrieve current driver settings */
254 tspub->get_params (tspub, &params);
255 /* On Axim a delay of 3 AC97 frame works ok */
256 params.delay = 3;
257 /* IRQ55 is touchscreen */
258 params.pen_irq = AXIMX5_IRQ (TOUCHSCREEN);
259 /* On Axim X5 the bottom-left is touchscreen origin, while the
260 * graphics origin is in top-left.
262 params.invert = 2;
263 /* Use a low pen detect threshold, otherwise on low pressure
264 * we often get very biased ADC readings.
266 if (!params.pdd)
267 params.pdd = 1;
268 if (!params.pil)
269 params.pil = 1;
271 tspub->set_params (tspub, &params);
272 tspub->apply_params (tspub);
274 set_irq_type(AXIMX5_IRQ (TOUCHSCREEN), IRQT_BOTHEDGE);
276 mq_driver_get ();
277 mq_device_enum (&mq_base, 1);
278 if (mq_base) {
279 tspub->codec->codec_ops->amplifier = aximx5_amplifier;
280 /* Initialize master volume */
281 mixer = tspub->codec->read_mixer (tspub->codec, SOUND_MIXER_VOLUME);
282 tspub->codec->write_mixer (tspub->codec, SOUND_MIXER_VOLUME, 0, 0);
283 tspub->codec->write_mixer (tspub->codec, SOUND_MIXER_VOLUME,
284 mixer & 0xff, mixer >> 8);
287 /* Start BMON sampling ... */
288 tspub->setup_auxconv (tspub, WM97XX_AC_BMON, BMON_AUX_SAMPLE_INTERVAL,
289 NULL);
290 /* Start AUX sampling ... */
291 tspub->setup_auxconv (tspub, WM97XX_AC_AUX1, BMON_AUX_SAMPLE_INTERVAL,
292 wm97xx_prepare_aux);
293 /* Register main Axim battery */
294 battery_class_register (&aximx5_main_battery);
295 /* ... and the backup battery */
296 battery_class_register (&aximx5_backup_battery);
298 return 0;
301 static void __exit
302 aximx5_ac97_exit(void)
304 tspub->setup_auxconv (tspub, WM97XX_AC_BMON, 0, NULL);
305 tspub->setup_auxconv (tspub, WM97XX_AC_AUX1, 0, NULL);
307 tspub->codec->codec_ops->amplifier = NULL;
308 mq_driver_put ();
311 module_init(aximx5_ac97_init);
312 module_exit(aximx5_ac97_exit);
314 MODULE_AUTHOR("Andrew Zabolotny <zap@homelink.ru>");
315 MODULE_DESCRIPTION("AC97 controller driver for Dell Axim X5");
316 MODULE_LICENSE("GPL");