Loading...
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); |