Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * SMBus driver for ACPI Embedded Controller (v0.1)
0004  *
0005  * Copyright (c) 2007 Alexey Starikovskiy
0006  */
0007 
0008 #define pr_fmt(fmt) "ACPI: " fmt
0009 
0010 #include <linux/acpi.h>
0011 #include <linux/wait.h>
0012 #include <linux/slab.h>
0013 #include <linux/delay.h>
0014 #include <linux/module.h>
0015 #include <linux/interrupt.h>
0016 #include "sbshc.h"
0017 
0018 #define ACPI_SMB_HC_CLASS   "smbus_host_ctl"
0019 #define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
0020 
0021 struct acpi_smb_hc {
0022     struct acpi_ec *ec;
0023     struct mutex lock;
0024     wait_queue_head_t wait;
0025     u8 offset;
0026     u8 query_bit;
0027     smbus_alarm_callback callback;
0028     void *context;
0029     bool done;
0030 };
0031 
0032 static int acpi_smbus_hc_add(struct acpi_device *device);
0033 static int acpi_smbus_hc_remove(struct acpi_device *device);
0034 
0035 static const struct acpi_device_id sbs_device_ids[] = {
0036     {"ACPI0001", 0},
0037     {"ACPI0005", 0},
0038     {"", 0},
0039 };
0040 
0041 MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
0042 
0043 static struct acpi_driver acpi_smb_hc_driver = {
0044     .name = "smbus_hc",
0045     .class = ACPI_SMB_HC_CLASS,
0046     .ids = sbs_device_ids,
0047     .ops = {
0048         .add = acpi_smbus_hc_add,
0049         .remove = acpi_smbus_hc_remove,
0050         },
0051 };
0052 
0053 union acpi_smb_status {
0054     u8 raw;
0055     struct {
0056         u8 status:5;
0057         u8 reserved:1;
0058         u8 alarm:1;
0059         u8 done:1;
0060     } fields;
0061 };
0062 
0063 enum acpi_smb_status_codes {
0064     SMBUS_OK = 0,
0065     SMBUS_UNKNOWN_FAILURE = 0x07,
0066     SMBUS_DEVICE_ADDRESS_NACK = 0x10,
0067     SMBUS_DEVICE_ERROR = 0x11,
0068     SMBUS_DEVICE_COMMAND_ACCESS_DENIED = 0x12,
0069     SMBUS_UNKNOWN_ERROR = 0x13,
0070     SMBUS_DEVICE_ACCESS_DENIED = 0x17,
0071     SMBUS_TIMEOUT = 0x18,
0072     SMBUS_HOST_UNSUPPORTED_PROTOCOL = 0x19,
0073     SMBUS_BUSY = 0x1a,
0074     SMBUS_PEC_ERROR = 0x1f,
0075 };
0076 
0077 enum acpi_smb_offset {
0078     ACPI_SMB_PROTOCOL = 0,  /* protocol, PEC */
0079     ACPI_SMB_STATUS = 1,    /* status */
0080     ACPI_SMB_ADDRESS = 2,   /* address */
0081     ACPI_SMB_COMMAND = 3,   /* command */
0082     ACPI_SMB_DATA = 4,  /* 32 data registers */
0083     ACPI_SMB_BLOCK_COUNT = 0x24,    /* number of data bytes */
0084     ACPI_SMB_ALARM_ADDRESS = 0x25,  /* alarm address */
0085     ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */
0086 };
0087 
0088 static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
0089 {
0090     return ec_read(hc->offset + address, data);
0091 }
0092 
0093 static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data)
0094 {
0095     return ec_write(hc->offset + address, data);
0096 }
0097 
0098 static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
0099 {
0100     if (wait_event_timeout(hc->wait, hc->done, msecs_to_jiffies(timeout)))
0101         return 0;
0102     return -ETIME;
0103 }
0104 
0105 static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
0106                   u8 address, u8 command, u8 *data, u8 length)
0107 {
0108     int ret = -EFAULT, i;
0109     u8 temp, sz = 0;
0110 
0111     if (!hc) {
0112         pr_err("host controller is not configured\n");
0113         return ret;
0114     }
0115 
0116     mutex_lock(&hc->lock);
0117     hc->done = false;
0118     if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
0119         goto end;
0120     if (temp) {
0121         ret = -EBUSY;
0122         goto end;
0123     }
0124     smb_hc_write(hc, ACPI_SMB_COMMAND, command);
0125     if (!(protocol & 0x01)) {
0126         smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length);
0127         for (i = 0; i < length; ++i)
0128             smb_hc_write(hc, ACPI_SMB_DATA + i, data[i]);
0129     }
0130     smb_hc_write(hc, ACPI_SMB_ADDRESS, address << 1);
0131     smb_hc_write(hc, ACPI_SMB_PROTOCOL, protocol);
0132     /*
0133      * Wait for completion. Save the status code, data size,
0134      * and data into the return package (if required by the protocol).
0135      */
0136     ret = wait_transaction_complete(hc, 1000);
0137     if (ret || !(protocol & 0x01))
0138         goto end;
0139     switch (protocol) {
0140     case SMBUS_RECEIVE_BYTE:
0141     case SMBUS_READ_BYTE:
0142         sz = 1;
0143         break;
0144     case SMBUS_READ_WORD:
0145         sz = 2;
0146         break;
0147     case SMBUS_READ_BLOCK:
0148         if (smb_hc_read(hc, ACPI_SMB_BLOCK_COUNT, &sz)) {
0149             ret = -EFAULT;
0150             goto end;
0151         }
0152         sz &= 0x1f;
0153         break;
0154     }
0155     for (i = 0; i < sz; ++i)
0156         smb_hc_read(hc, ACPI_SMB_DATA + i, &data[i]);
0157       end:
0158     mutex_unlock(&hc->lock);
0159     return ret;
0160 }
0161 
0162 int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address,
0163             u8 command, u8 *data)
0164 {
0165     return acpi_smbus_transaction(hc, protocol, address, command, data, 0);
0166 }
0167 
0168 EXPORT_SYMBOL_GPL(acpi_smbus_read);
0169 
0170 int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address,
0171              u8 command, u8 *data, u8 length)
0172 {
0173     return acpi_smbus_transaction(hc, protocol, address, command, data, length);
0174 }
0175 
0176 EXPORT_SYMBOL_GPL(acpi_smbus_write);
0177 
0178 int acpi_smbus_register_callback(struct acpi_smb_hc *hc,
0179                  smbus_alarm_callback callback, void *context)
0180 {
0181     mutex_lock(&hc->lock);
0182     hc->callback = callback;
0183     hc->context = context;
0184     mutex_unlock(&hc->lock);
0185     return 0;
0186 }
0187 
0188 EXPORT_SYMBOL_GPL(acpi_smbus_register_callback);
0189 
0190 int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc)
0191 {
0192     mutex_lock(&hc->lock);
0193     hc->callback = NULL;
0194     hc->context = NULL;
0195     mutex_unlock(&hc->lock);
0196     acpi_os_wait_events_complete();
0197     return 0;
0198 }
0199 
0200 EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback);
0201 
0202 static inline void acpi_smbus_callback(void *context)
0203 {
0204     struct acpi_smb_hc *hc = context;
0205     if (hc->callback)
0206         hc->callback(hc->context);
0207 }
0208 
0209 static int smbus_alarm(void *context)
0210 {
0211     struct acpi_smb_hc *hc = context;
0212     union acpi_smb_status status;
0213     u8 address;
0214     if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw))
0215         return 0;
0216     /* Check if it is only a completion notify */
0217     if (status.fields.done && status.fields.status == SMBUS_OK) {
0218         hc->done = true;
0219         wake_up(&hc->wait);
0220     }
0221     if (!status.fields.alarm)
0222         return 0;
0223     mutex_lock(&hc->lock);
0224     smb_hc_read(hc, ACPI_SMB_ALARM_ADDRESS, &address);
0225     status.fields.alarm = 0;
0226     smb_hc_write(hc, ACPI_SMB_STATUS, status.raw);
0227     /* We are only interested in events coming from known devices */
0228     switch (address >> 1) {
0229         case ACPI_SBS_CHARGER:
0230         case ACPI_SBS_MANAGER:
0231         case ACPI_SBS_BATTERY:
0232             acpi_os_execute(OSL_NOTIFY_HANDLER,
0233                     acpi_smbus_callback, hc);
0234     }
0235     mutex_unlock(&hc->lock);
0236     return 0;
0237 }
0238 
0239 typedef int (*acpi_ec_query_func) (void *data);
0240 
0241 extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
0242                   acpi_handle handle, acpi_ec_query_func func,
0243                   void *data);
0244 
0245 static int acpi_smbus_hc_add(struct acpi_device *device)
0246 {
0247     int status;
0248     unsigned long long val;
0249     struct acpi_smb_hc *hc;
0250 
0251     if (!device)
0252         return -EINVAL;
0253 
0254     status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
0255     if (ACPI_FAILURE(status)) {
0256         pr_err("error obtaining _EC.\n");
0257         return -EIO;
0258     }
0259 
0260     strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME);
0261     strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS);
0262 
0263     hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL);
0264     if (!hc)
0265         return -ENOMEM;
0266     mutex_init(&hc->lock);
0267     init_waitqueue_head(&hc->wait);
0268 
0269     hc->ec = acpi_driver_data(device->parent);
0270     hc->offset = (val >> 8) & 0xff;
0271     hc->query_bit = val & 0xff;
0272     device->driver_data = hc;
0273 
0274     acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
0275     dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
0276          hc->offset, hc->query_bit);
0277 
0278     return 0;
0279 }
0280 
0281 extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
0282 
0283 static int acpi_smbus_hc_remove(struct acpi_device *device)
0284 {
0285     struct acpi_smb_hc *hc;
0286 
0287     if (!device)
0288         return -EINVAL;
0289 
0290     hc = acpi_driver_data(device);
0291     acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
0292     acpi_os_wait_events_complete();
0293     kfree(hc);
0294     device->driver_data = NULL;
0295     return 0;
0296 }
0297 
0298 module_acpi_driver(acpi_smb_hc_driver);
0299 
0300 MODULE_LICENSE("GPL");
0301 MODULE_AUTHOR("Alexey Starikovskiy");
0302 MODULE_DESCRIPTION("ACPI SMBus HC driver");