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