^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * SMBus driver for ACPI Embedded Controller (v0.1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2007 Alexey Starikovskiy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "sbshc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define PREFIX "ACPI: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define ACPI_SMB_HC_CLASS "smbus_host_ctl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct acpi_smb_hc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct acpi_ec *ec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) wait_queue_head_t wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) u8 offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u8 query_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) smbus_alarm_callback callback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void *context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) bool done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int acpi_smbus_hc_add(struct acpi_device *device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static int acpi_smbus_hc_remove(struct acpi_device *device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static const struct acpi_device_id sbs_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {"ACPI0001", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {"ACPI0005", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static struct acpi_driver acpi_smb_hc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .name = "smbus_hc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .class = ACPI_SMB_HC_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) .ids = sbs_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .add = acpi_smbus_hc_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .remove = acpi_smbus_hc_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) union acpi_smb_status {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u8 raw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) u8 status:5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) u8 reserved:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u8 alarm:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) u8 done:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) } fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) enum acpi_smb_status_codes {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) SMBUS_OK = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) SMBUS_UNKNOWN_FAILURE = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) SMBUS_DEVICE_ADDRESS_NACK = 0x10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) SMBUS_DEVICE_ERROR = 0x11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) SMBUS_DEVICE_COMMAND_ACCESS_DENIED = 0x12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) SMBUS_UNKNOWN_ERROR = 0x13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) SMBUS_DEVICE_ACCESS_DENIED = 0x17,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) SMBUS_TIMEOUT = 0x18,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) SMBUS_HOST_UNSUPPORTED_PROTOCOL = 0x19,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) SMBUS_BUSY = 0x1a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) SMBUS_PEC_ERROR = 0x1f,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) enum acpi_smb_offset {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ACPI_SMB_PROTOCOL = 0, /* protocol, PEC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ACPI_SMB_STATUS = 1, /* status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ACPI_SMB_ADDRESS = 2, /* address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ACPI_SMB_COMMAND = 3, /* command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ACPI_SMB_DATA = 4, /* 32 data registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ACPI_SMB_BLOCK_COUNT = 0x24, /* number of data bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ACPI_SMB_ALARM_ADDRESS = 0x25, /* alarm address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return ec_read(hc->offset + address, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return ec_write(hc->offset + address, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (wait_event_timeout(hc->wait, hc->done, msecs_to_jiffies(timeout)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return -ETIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u8 address, u8 command, u8 *data, u8 length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int ret = -EFAULT, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) u8 temp, sz = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (!hc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) printk(KERN_ERR PREFIX "host controller is not configured\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) mutex_lock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) hc->done = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (temp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) smb_hc_write(hc, ACPI_SMB_COMMAND, command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (!(protocol & 0x01)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) for (i = 0; i < length; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) smb_hc_write(hc, ACPI_SMB_DATA + i, data[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) smb_hc_write(hc, ACPI_SMB_ADDRESS, address << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) smb_hc_write(hc, ACPI_SMB_PROTOCOL, protocol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * Wait for completion. Save the status code, data size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * and data into the return package (if required by the protocol).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ret = wait_transaction_complete(hc, 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (ret || !(protocol & 0x01))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) switch (protocol) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) case SMBUS_RECEIVE_BYTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) case SMBUS_READ_BYTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) sz = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) case SMBUS_READ_WORD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) sz = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) case SMBUS_READ_BLOCK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (smb_hc_read(hc, ACPI_SMB_BLOCK_COUNT, &sz)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) sz &= 0x1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) for (i = 0; i < sz; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) smb_hc_read(hc, ACPI_SMB_DATA + i, &data[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) mutex_unlock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) u8 command, u8 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return acpi_smbus_transaction(hc, protocol, address, command, data, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) EXPORT_SYMBOL_GPL(acpi_smbus_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) u8 command, u8 *data, u8 length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return acpi_smbus_transaction(hc, protocol, address, command, data, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) EXPORT_SYMBOL_GPL(acpi_smbus_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) int acpi_smbus_register_callback(struct acpi_smb_hc *hc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) smbus_alarm_callback callback, void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) mutex_lock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) hc->callback = callback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) hc->context = context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) mutex_unlock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) EXPORT_SYMBOL_GPL(acpi_smbus_register_callback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) mutex_lock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) hc->callback = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) hc->context = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) mutex_unlock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) acpi_os_wait_events_complete();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static inline void acpi_smbus_callback(void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct acpi_smb_hc *hc = context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (hc->callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) hc->callback(hc->context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int smbus_alarm(void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct acpi_smb_hc *hc = context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) union acpi_smb_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) u8 address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Check if it is only a completion notify */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (status.fields.done && status.fields.status == SMBUS_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) hc->done = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) wake_up(&hc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (!status.fields.alarm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) mutex_lock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) smb_hc_read(hc, ACPI_SMB_ALARM_ADDRESS, &address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) status.fields.alarm = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) smb_hc_write(hc, ACPI_SMB_STATUS, status.raw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* We are only interested in events coming from known devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) switch (address >> 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case ACPI_SBS_CHARGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) case ACPI_SBS_MANAGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) case ACPI_SBS_BATTERY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) acpi_os_execute(OSL_NOTIFY_HANDLER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) acpi_smbus_callback, hc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) default:;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) mutex_unlock(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) typedef int (*acpi_ec_query_func) (void *data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) acpi_handle handle, acpi_ec_query_func func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) void *data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static int acpi_smbus_hc_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) unsigned long long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct acpi_smb_hc *hc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) printk(KERN_ERR PREFIX "error obtaining _EC.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (!hc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) mutex_init(&hc->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) init_waitqueue_head(&hc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) hc->ec = acpi_driver_data(device->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) hc->offset = (val >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) hc->query_bit = val & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) device->driver_data = hc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) hc->offset, hc->query_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static int acpi_smbus_hc_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct acpi_smb_hc *hc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) hc = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) acpi_os_wait_events_complete();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) kfree(hc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) device->driver_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) module_acpi_driver(acpi_smb_hc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) MODULE_AUTHOR("Alexey Starikovskiy");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) MODULE_DESCRIPTION("ACPI SMBus HC driver");