stm32mp157/lishanwen/led_platform/led_driver.c
2026-02-08 21:27:46 +08:00

163 lines
4.1 KiB
C

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/of.h>
static dev_t led_dev;
static struct cdev *led_cdev;
static struct class *led_class;
static struct device *led_device;
static volatile uint32_t *RCC_PLL4CR;
static volatile uint32_t *RCC_MP_AHB4ENSETR;
static volatile uint32_t *GPIOA_MODER;
static volatile uint32_t *GPIOA_BSRR;
static int led_open(struct inode *inode, struct file *filp)
{
*RCC_PLL4CR |= (1 << 0);
while ((*RCC_PLL4CR & (1 << 1)) == 0);
*RCC_MP_AHB4ENSETR |= (1 << 0);
*GPIOA_MODER &= ~(3 << 20);
*GPIOA_MODER |= (1 << 20);
printk(KERN_DEBUG "LED device opened.\r\n");
return 0;
}
static int led_close(struct inode *inode, struct file *filp)
{
printk(KERN_DEBUG "LED device closed.\r\n");
return 0;
}
static int led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
char val;
copy_from_user(&val, buff, 1);
if (val) {
*GPIOA_BSRR = (1 << 26);
} else {
*GPIOA_BSRR = (1 << 10);
}
return 0;
}
static int led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
return 0;
}
static struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_close,
.write = led_write,
.read = led_read,
};
static int led_probe(struct platform_device *pdev)
{
struct resource *res;
int ret;
printk(KERN_ERR "led_probe, %d\r\n", __LINE__);
led_cdev = cdev_alloc();
if (led_cdev == NULL) {
printk(KERN_ERR "Failed to allocate cdev\r\n");
return -ENOMEM;
}
ret = alloc_chrdev_region(&led_dev, 0, 1, "led");
if (ret != 0) {
printk(KERN_ERR "Failed to allocate chrdev region\r\n");
return ret;
}
led_cdev->owner = THIS_MODULE;
led_cdev->ops = &led_ops;
cdev_add(led_cdev, led_dev, 1);
led_class = class_create(THIS_MODULE, "led_class");
if (led_class == NULL) {
printk(KERN_ERR "Failed to create class\r\n");
return -1;
}
led_device = device_create(led_class, NULL, led_dev, NULL, "led_jzh");
if (IS_ERR(led_device)) {
printk(KERN_ERR "Failed to create device\r\n");
return -1;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
RCC_PLL4CR = ioremap(res->start, res->end - res->start + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
RCC_MP_AHB4ENSETR = ioremap(res->start, res->end - res->start + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
GPIOA_MODER = ioremap(res->start, res->end - res->start + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
GPIOA_BSRR = ioremap(res->start, res->end - res->start + 1);
return 0;
}
static int led_remove(struct platform_device *pdev)
{
cdev_del(led_cdev);
unregister_chrdev_region(led_dev, 1);
device_destroy(led_class, led_dev);
class_destroy(led_class);
iounmap(RCC_PLL4CR);
iounmap(RCC_MP_AHB4ENSETR);
iounmap(GPIOA_MODER);
iounmap(GPIOA_BSRR);
return 0;
}
static const struct of_device_id led_of_match[] = {
{ .compatible = "led_jzh", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, led_of_match);
static struct platform_driver led_driver = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "led_jzh",
.of_match_table = led_of_match,
},
};
static int __init led_driver_init(void)
{
int ret;
ret = platform_driver_register(&led_driver);
if (ret) {
printk(KERN_ERR "Failed to register LED platform driver\r\n");
return ret;
} else {
printk(KERN_ERR "Succeeded to register LED platform driver\r\n");
}
return 0;
}
static void __exit led_driver_exit(void)
{
platform_driver_unregister(&led_driver);
}
module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jzhgonha@163.com");
MODULE_VERSION("V0.1");
MODULE_DESCRIPTION("A simple LED driver for STM32MP157");