151 lines
4.1 KiB
C
151 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 <linux/of.h>
|
||
|
|
#include <asm/io.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 __init led_init(void)
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
struct device_node *led_node;
|
||
|
|
uint32_t addr_rcc_pll4cr;
|
||
|
|
uint32_t addr_rcc_mp_ahb4ensetr;
|
||
|
|
uint32_t addr_gpioa_moder;
|
||
|
|
uint32_t addr_gpioa_bsrr;
|
||
|
|
|
||
|
|
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, "led0");
|
||
|
|
if (IS_ERR(led_device)) {
|
||
|
|
printk(KERN_ERR "Failed to create device\r\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
led_node = of_find_node_by_path("/jzhled");
|
||
|
|
if (led_node == NULL) {
|
||
|
|
printk(KERN_ERR "file=%s, line=%d\r\n", __FILE__, __LINE__);
|
||
|
|
goto no_led_node;
|
||
|
|
}
|
||
|
|
if (of_property_read_u32_index(led_node, "reg", 0, &addr_rcc_pll4cr)) {
|
||
|
|
printk(KERN_ERR "file=%s, line=%d\r\n", __FILE__, __LINE__);
|
||
|
|
goto of_error;
|
||
|
|
}
|
||
|
|
if (of_property_read_u32_index(led_node, "reg", 2, &addr_rcc_mp_ahb4ensetr)) {
|
||
|
|
printk(KERN_ERR "file=%s, line=%d\r\n", __FILE__, __LINE__);
|
||
|
|
goto of_error;
|
||
|
|
}
|
||
|
|
if (of_property_read_u32_index(led_node, "reg", 4, &addr_gpioa_moder)) {
|
||
|
|
printk(KERN_ERR "file=%s, line=%d\r\n", __FILE__, __LINE__);
|
||
|
|
goto of_error;
|
||
|
|
}
|
||
|
|
if (of_property_read_u32_index(led_node, "reg", 6, &addr_gpioa_bsrr)) {
|
||
|
|
printk(KERN_ERR "file=%s, line=%d\r\n", __FILE__, __LINE__);
|
||
|
|
goto of_error;
|
||
|
|
}
|
||
|
|
RCC_PLL4CR = ioremap(addr_rcc_pll4cr, 4);
|
||
|
|
RCC_MP_AHB4ENSETR = ioremap(addr_rcc_mp_ahb4ensetr, 4);
|
||
|
|
GPIOA_MODER = ioremap(addr_gpioa_moder, 4);
|
||
|
|
GPIOA_BSRR = ioremap(addr_gpioa_bsrr, 4);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
of_error:
|
||
|
|
printk(KERN_ERR "Failed to get led node reg\r\n");
|
||
|
|
return -1;
|
||
|
|
no_led_node:
|
||
|
|
printk(KERN_ERR "No led node found\r\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void __exit led_exit(void)
|
||
|
|
{
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
module_init(led_init);
|
||
|
|
module_exit(led_exit);
|
||
|
|
MODULE_LICENSE("GPL");
|
||
|
|
MODULE_AUTHOR("jzhgonha@163.com");
|
||
|
|
MODULE_VERSION("V0.1");
|
||
|
|
MODULE_DESCRIPTION("A simple LED driver for STM32MP157");
|