summaryrefslogtreecommitdiff
path: root/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.c
blob: d138220e96a2840c839d590b01b7a9fd0890fec2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Basic KB3310B Embedded Controller support for the YeeLoong 2F netbook
 *
 *  Copyright (C) 2008 Lemote Inc.
 *  Author: liujl <liujl@lemote.com>, 2008-04-20
 */

#include <linux/io.h>
#include <linux/export.h>
#include <linux/spinlock.h>
#include <linux/delay.h>

#include "ec_kb3310b.h"

static DEFINE_SPINLOCK(index_access_lock);
static DEFINE_SPINLOCK(port_access_lock);

unsigned char ec_read(unsigned short addr)
{
	unsigned char value;
	unsigned long flags;

	spin_lock_irqsave(&index_access_lock, flags);
	outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
	outb((addr & 0x00ff), EC_IO_PORT_LOW);
	value = inb(EC_IO_PORT_DATA);
	spin_unlock_irqrestore(&index_access_lock, flags);

	return value;
}
EXPORT_SYMBOL_GPL(ec_read);

void ec_write(unsigned short addr, unsigned char val)
{
	unsigned long flags;

	spin_lock_irqsave(&index_access_lock, flags);
	outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
	outb((addr & 0x00ff), EC_IO_PORT_LOW);
	outb(val, EC_IO_PORT_DATA);
	/*  flush the write action */
	inb(EC_IO_PORT_DATA);
	spin_unlock_irqrestore(&index_access_lock, flags);
}
EXPORT_SYMBOL_GPL(ec_write);

/*
 * This function is used for EC command writes and corresponding status queries.
 */
int ec_query_seq(unsigned char cmd)
{
	int timeout;
	unsigned char status;
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&port_access_lock, flags);

	/* make chip goto reset mode */
	udelay(EC_REG_DELAY);
	outb(cmd, EC_CMD_PORT);
	udelay(EC_REG_DELAY);

	/* check if the command is received by ec */
	timeout = EC_CMD_TIMEOUT;
	status = inb(EC_STS_PORT);
	while (timeout-- && (status & (1 << 1))) {
		status = inb(EC_STS_PORT);
		udelay(EC_REG_DELAY);
	}

	spin_unlock_irqrestore(&port_access_lock, flags);

	if (timeout <= 0) {
		printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
		ret = -EINVAL;
	} else
		printk(KERN_INFO
			   "(%x/%d)ec issued command %d status : 0x%x\n",
			   timeout, EC_CMD_TIMEOUT - timeout, cmd, status);

	return ret;
}
EXPORT_SYMBOL_GPL(ec_query_seq);

/*
 * Send query command to EC to get the proper event number
 */
int ec_query_event_num(void)
{
	return ec_query_seq(CMD_GET_EVENT_NUM);
}
EXPORT_SYMBOL(ec_query_event_num);

/*
 * Get event number from EC
 *
 * NOTE: This routine must follow the query_event_num function in the
 * interrupt.
 */
int ec_get_event_num(void)
{
	int timeout = 100;
	unsigned char value;
	unsigned char status;

	udelay(EC_REG_DELAY);
	status = inb(EC_STS_PORT);
	udelay(EC_REG_DELAY);
	while (timeout-- && !(status & (1 << 0))) {
		status = inb(EC_STS_PORT);
		udelay(EC_REG_DELAY);
	}
	if (timeout <= 0) {
		pr_info("%s: get event number timeout.\n", __func__);

		return -EINVAL;
	}
	value = inb(EC_DAT_PORT);
	udelay(EC_REG_DELAY);

	return value;
}
EXPORT_SYMBOL(ec_get_event_num);