Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  dell-smo8800.c - Dell Latitude ACPI SMO88XX freefall sensor driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *  Copyright (C) 2014 Pali Rohár <pali@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *  This is loosely based on lis3lv02d driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #define DRIVER_NAME "smo8800"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) struct smo8800_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	u32 irq;                     /* acpi device irq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	atomic_t counter;            /* count after last read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	struct miscdevice miscdev;   /* for /dev/freefall */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	unsigned long misc_opened;   /* whether the device is open */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	wait_queue_head_t misc_wait; /* Wait queue for the misc dev */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	struct device *dev;          /* acpi device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) static irqreturn_t smo8800_interrupt_quick(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	struct smo8800_device *smo8800 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	atomic_inc(&smo8800->counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	wake_up_interruptible(&smo8800->misc_wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	return IRQ_WAKE_THREAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) static irqreturn_t smo8800_interrupt_thread(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	struct smo8800_device *smo8800 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	dev_info(smo8800->dev, "detected free fall\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) static acpi_status smo8800_get_resource(struct acpi_resource *resource,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 					void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	struct acpi_resource_extended_irq *irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	if (resource->type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	irq = &resource->data.extended_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	if (!irq || !irq->interrupt_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	*((u32 *)context) = irq->interrupts[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	return AE_CTRL_TERMINATE;
^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) static u32 smo8800_get_irq(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	u32 irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 				     smo8800_get_resource, &irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		dev_err(&device->dev, "acpi_walk_resources failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 				 size_t count, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	struct smo8800_device *smo8800 = container_of(file->private_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 					 struct smo8800_device, miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	u32 data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	unsigned char byte_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	ssize_t retval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	if (count < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	atomic_set(&smo8800->counter, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	retval = wait_event_interruptible(smo8800->misc_wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 				(data = atomic_xchg(&smo8800->counter, 0)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	retval = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	if (data < 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		byte_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		byte_data = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	if (put_user(byte_data, buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		retval = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int smo8800_misc_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	struct smo8800_device *smo8800 = container_of(file->private_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 					 struct smo8800_device, miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	if (test_and_set_bit(0, &smo8800->misc_opened))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		return -EBUSY; /* already open */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	atomic_set(&smo8800->counter, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int smo8800_misc_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	struct smo8800_device *smo8800 = container_of(file->private_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 					 struct smo8800_device, miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	clear_bit(0, &smo8800->misc_opened); /* release the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static const struct file_operations smo8800_misc_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	.owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	.read = smo8800_misc_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	.open = smo8800_misc_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	.release = smo8800_misc_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static int smo8800_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	struct smo8800_device *smo8800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	smo8800 = devm_kzalloc(&device->dev, sizeof(*smo8800), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	if (!smo8800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		dev_err(&device->dev, "failed to allocate device data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	smo8800->dev = &device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	smo8800->miscdev.minor = MISC_DYNAMIC_MINOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	smo8800->miscdev.name = "freefall";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	smo8800->miscdev.fops = &smo8800_misc_fops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	init_waitqueue_head(&smo8800->misc_wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	err = misc_register(&smo8800->miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		dev_err(&device->dev, "failed to register misc dev: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	device->driver_data = smo8800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	smo8800->irq = smo8800_get_irq(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	if (!smo8800->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		dev_err(&device->dev, "failed to obtain IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	err = request_threaded_irq(smo8800->irq, smo8800_interrupt_quick,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 				   smo8800_interrupt_thread,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 				   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 				   DRIVER_NAME, smo8800);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		dev_err(&device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			"failed to request thread for IRQ %d: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 			smo8800->irq, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	dev_dbg(&device->dev, "device /dev/freefall registered with IRQ %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		 smo8800->irq);
^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) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	misc_deregister(&smo8800->miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int smo8800_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	struct smo8800_device *smo8800 = device->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	free_irq(smo8800->irq, smo8800);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	misc_deregister(&smo8800->miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	dev_dbg(&device->dev, "device /dev/freefall unregistered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /* NOTE: Keep this list in sync with drivers/i2c/busses/i2c-i801.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static const struct acpi_device_id smo8800_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	{ "SMO8800", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	{ "SMO8801", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	{ "SMO8810", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	{ "SMO8811", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	{ "SMO8820", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	{ "SMO8821", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	{ "SMO8830", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	{ "SMO8831", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	{ "", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) MODULE_DEVICE_TABLE(acpi, smo8800_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static struct acpi_driver smo8800_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	.name = DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	.class = "Latitude",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	.ids = smo8800_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	.ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		.add = smo8800_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		.remove = smo8800_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	.owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) module_acpi_driver(smo8800_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO88XX)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) MODULE_AUTHOR("Sonal Santan, Pali Rohár");