Merge remote-tracking branches 'asoc/topic/tegra', 'asoc/topic/tlv320aic23', 'asoc...
[sfrench/cifs-2.6.git] / arch / mips / loongson64 / lemote-2f / ec_kb3310b.c
1 /*
2  * Basic KB3310B Embedded Controller support for the YeeLoong 2F netbook
3  *
4  *  Copyright (C) 2008 Lemote Inc.
5  *  Author: liujl <liujl@lemote.com>, 2008-04-20
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  */
12
13 #include <linux/io.h>
14 #include <linux/export.h>
15 #include <linux/spinlock.h>
16 #include <linux/delay.h>
17
18 #include "ec_kb3310b.h"
19
20 static DEFINE_SPINLOCK(index_access_lock);
21 static DEFINE_SPINLOCK(port_access_lock);
22
23 unsigned char ec_read(unsigned short addr)
24 {
25         unsigned char value;
26         unsigned long flags;
27
28         spin_lock_irqsave(&index_access_lock, flags);
29         outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
30         outb((addr & 0x00ff), EC_IO_PORT_LOW);
31         value = inb(EC_IO_PORT_DATA);
32         spin_unlock_irqrestore(&index_access_lock, flags);
33
34         return value;
35 }
36 EXPORT_SYMBOL_GPL(ec_read);
37
38 void ec_write(unsigned short addr, unsigned char val)
39 {
40         unsigned long flags;
41
42         spin_lock_irqsave(&index_access_lock, flags);
43         outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
44         outb((addr & 0x00ff), EC_IO_PORT_LOW);
45         outb(val, EC_IO_PORT_DATA);
46         /*  flush the write action */
47         inb(EC_IO_PORT_DATA);
48         spin_unlock_irqrestore(&index_access_lock, flags);
49 }
50 EXPORT_SYMBOL_GPL(ec_write);
51
52 /*
53  * This function is used for EC command writes and corresponding status queries.
54  */
55 int ec_query_seq(unsigned char cmd)
56 {
57         int timeout;
58         unsigned char status;
59         unsigned long flags;
60         int ret = 0;
61
62         spin_lock_irqsave(&port_access_lock, flags);
63
64         /* make chip goto reset mode */
65         udelay(EC_REG_DELAY);
66         outb(cmd, EC_CMD_PORT);
67         udelay(EC_REG_DELAY);
68
69         /* check if the command is received by ec */
70         timeout = EC_CMD_TIMEOUT;
71         status = inb(EC_STS_PORT);
72         while (timeout-- && (status & (1 << 1))) {
73                 status = inb(EC_STS_PORT);
74                 udelay(EC_REG_DELAY);
75         }
76
77         spin_unlock_irqrestore(&port_access_lock, flags);
78
79         if (timeout <= 0) {
80                 printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
81                 ret = -EINVAL;
82         } else
83                 printk(KERN_INFO
84                            "(%x/%d)ec issued command %d status : 0x%x\n",
85                            timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
86
87         return ret;
88 }
89 EXPORT_SYMBOL_GPL(ec_query_seq);
90
91 /*
92  * Send query command to EC to get the proper event number
93  */
94 int ec_query_event_num(void)
95 {
96         return ec_query_seq(CMD_GET_EVENT_NUM);
97 }
98 EXPORT_SYMBOL(ec_query_event_num);
99
100 /*
101  * Get event number from EC
102  *
103  * NOTE: This routine must follow the query_event_num function in the
104  * interrupt.
105  */
106 int ec_get_event_num(void)
107 {
108         int timeout = 100;
109         unsigned char value;
110         unsigned char status;
111
112         udelay(EC_REG_DELAY);
113         status = inb(EC_STS_PORT);
114         udelay(EC_REG_DELAY);
115         while (timeout-- && !(status & (1 << 0))) {
116                 status = inb(EC_STS_PORT);
117                 udelay(EC_REG_DELAY);
118         }
119         if (timeout <= 0) {
120                 pr_info("%s: get event number timeout.\n", __func__);
121
122                 return -EINVAL;
123         }
124         value = inb(EC_DAT_PORT);
125         udelay(EC_REG_DELAY);
126
127         return value;
128 }
129 EXPORT_SYMBOL(ec_get_event_num);