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/module.h>
14 #include <linux/spinlock.h>
15 #include <linux/delay.h>
16 
17 #include "ec_kb3310b.h"
18 
19 static DEFINE_SPINLOCK(index_access_lock);
20 static DEFINE_SPINLOCK(port_access_lock);
21 
ec_read(unsigned short addr)22 unsigned char ec_read(unsigned short addr)
23 {
24 	unsigned char value;
25 	unsigned long flags;
26 
27 	spin_lock_irqsave(&index_access_lock, flags);
28 	outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
29 	outb((addr & 0x00ff), EC_IO_PORT_LOW);
30 	value = inb(EC_IO_PORT_DATA);
31 	spin_unlock_irqrestore(&index_access_lock, flags);
32 
33 	return value;
34 }
35 EXPORT_SYMBOL_GPL(ec_read);
36 
ec_write(unsigned short addr,unsigned char val)37 void ec_write(unsigned short addr, unsigned char val)
38 {
39 	unsigned long flags;
40 
41 	spin_lock_irqsave(&index_access_lock, flags);
42 	outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
43 	outb((addr & 0x00ff), EC_IO_PORT_LOW);
44 	outb(val, EC_IO_PORT_DATA);
45 	/*  flush the write action */
46 	inb(EC_IO_PORT_DATA);
47 	spin_unlock_irqrestore(&index_access_lock, flags);
48 }
49 EXPORT_SYMBOL_GPL(ec_write);
50 
51 /*
52  * This function is used for EC command writes and corresponding status queries.
53  */
ec_query_seq(unsigned char cmd)54 int ec_query_seq(unsigned char cmd)
55 {
56 	int timeout;
57 	unsigned char status;
58 	unsigned long flags;
59 	int ret = 0;
60 
61 	spin_lock_irqsave(&port_access_lock, flags);
62 
63 	/* make chip goto reset mode */
64 	udelay(EC_REG_DELAY);
65 	outb(cmd, EC_CMD_PORT);
66 	udelay(EC_REG_DELAY);
67 
68 	/* check if the command is received by ec */
69 	timeout = EC_CMD_TIMEOUT;
70 	status = inb(EC_STS_PORT);
71 	while (timeout-- && (status & (1 << 1))) {
72 		status = inb(EC_STS_PORT);
73 		udelay(EC_REG_DELAY);
74 	}
75 
76 	spin_unlock_irqrestore(&port_access_lock, flags);
77 
78 	if (timeout <= 0) {
79 		printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
80 		ret = -EINVAL;
81 	} else
82 		printk(KERN_INFO
83 			   "(%x/%d)ec issued command %d status : 0x%x\n",
84 			   timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
85 
86 	return ret;
87 }
88 EXPORT_SYMBOL_GPL(ec_query_seq);
89 
90 /*
91  * Send query command to EC to get the proper event number
92  */
ec_query_event_num(void)93 int ec_query_event_num(void)
94 {
95 	return ec_query_seq(CMD_GET_EVENT_NUM);
96 }
97 EXPORT_SYMBOL(ec_query_event_num);
98 
99 /*
100  * Get event number from EC
101  *
102  * NOTE: This routine must follow the query_event_num function in the
103  * interrupt.
104  */
ec_get_event_num(void)105 int ec_get_event_num(void)
106 {
107 	int timeout = 100;
108 	unsigned char value;
109 	unsigned char status;
110 
111 	udelay(EC_REG_DELAY);
112 	status = inb(EC_STS_PORT);
113 	udelay(EC_REG_DELAY);
114 	while (timeout-- && !(status & (1 << 0))) {
115 		status = inb(EC_STS_PORT);
116 		udelay(EC_REG_DELAY);
117 	}
118 	if (timeout <= 0) {
119 		pr_info("%s: get event number timeout.\n", __func__);
120 
121 		return -EINVAL;
122 	}
123 	value = inb(EC_DAT_PORT);
124 	udelay(EC_REG_DELAY);
125 
126 	return value;
127 }
128 EXPORT_SYMBOL(ec_get_event_num);
129