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
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>
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
)
57 while (i
< 11 && val
>= dc
[i
+ 1])
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
)
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
)
88 static int aximx5_m_get_min_voltage (struct battery
*bat
)
93 static int aximx5_m_get_voltage (struct battery
*bat
)
95 int bmon
= tspub
->get_auxconv (tspub
, WM97XX_AC_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
= {
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.
136 static int aximx5_b_get_min_charge (struct battery
*bat
)
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
)
153 static int aximx5_b_get_min_voltage (struct battery
*bat
)
158 static int aximx5_b_get_voltage (struct battery
*bat
)
160 int aux
= tspub
->get_auxconv (tspub
, WM97XX_AC_AUX1
);
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
= {
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 */
203 /*----------------------------------------------* Amplifier power *----------*/
205 /* Update the Axim-specific GPIOs so that power amplifier is enabled/disabled
208 static int aximx5_amplifier (struct ac97_codec
*codec
, int on
)
210 static int power_on
= 0;
214 if (power_on
!= on
) {
215 mq_base
->set_power (mq_base
, MEDIAQ_11XX_SPI_DEVICE_ID
, 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
);
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
);
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
);
239 aximx5_ac97_init(void)
241 wm97xx_params params
;
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");
253 /* Retrieve current driver settings */
254 tspub
->get_params (tspub
, ¶ms
);
255 /* On Axim a delay of 3 AC97 frame works ok */
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.
263 /* Use a low pen detect threshold, otherwise on low pressure
264 * we often get very biased ADC readings.
271 tspub
->set_params (tspub
, ¶ms
);
272 tspub
->apply_params (tspub
);
274 set_irq_type(AXIMX5_IRQ (TOUCHSCREEN
), IRQT_BOTHEDGE
);
277 mq_device_enum (&mq_base
, 1);
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
,
290 /* Start AUX sampling ... */
291 tspub
->setup_auxconv (tspub
, WM97XX_AC_AUX1
, BMON_AUX_SAMPLE_INTERVAL
,
293 /* Register main Axim battery */
294 battery_class_register (&aximx5_main_battery
);
295 /* ... and the backup battery */
296 battery_class_register (&aximx5_backup_battery
);
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
;
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");