Đề bài
LED nối GPIO17 (chân 11) qua trở 330 Ω xuống GND. Viết module led_kmod: ioremap vùng GPIO 0x3F200000, đặt GPIO17 làm output, tạo /dev/led — ghi 1 thì LED sáng, 0 thì tắt, đọc ra mức hiện tại. Khi gỡ module phải tắt LED và iounmap.
000 → GPIO17 là INPUT0 · ghi 1 → chân lên mức cao · đọc ra 00 · ghi 1 → chân xuống mức thấp · đọc ra 00 · mức thật trên chân GPIO0–31GPIO17 nằm ở bit 23:21 của GPFSEL1 (000 input, 001 output) và là bit 17 của GPSET0, GPCLR0, GPLEV0. Chân chưa là output thì ghi GPSET0 không làm LED sáng.
1// led_kmod.c – điều khiển LED ở GPIO17 qua thanh ghi (Pi Zero 2 W)2#include <linux/module.h>3#include <linux/miscdevice.h>4#include <linux/fs.h>5#include <linux/io.h>6#include <linux/bits.h>7#include <linux/uaccess.h>89#define GPIO_PHYS 0x3F200000 /* 0x3F000000 + 0x200000 */10#define GPIO_SIZE 0x10011#define GPFSEL1 0x0412#define GPSET0 0x1C13#define GPCLR0 0x2814#define GPLEV0 0x3415#define LED_PIN 171617static void __iomem *gpio;1819static ssize_t led_write(struct file *f, const char __user *buf,20size_t n, loff_t *off)21{22char c;23if (!n || get_user(c, buf))24return -EFAULT;25if (c == '1')26writel(BIT(LED_PIN), gpio + GPSET0);27else if (c == '0')28writel(BIT(LED_PIN), gpio + GPCLR0);29return n;30}3132static ssize_t led_read(struct file *f, char __user *buf,33size_t n, loff_t *off)34{35char s[2] = { '0', '\n' };36if (readl(gpio + GPLEV0) & BIT(LED_PIN))37s[0] = '1';38return simple_read_from_buffer(buf, n, off, s, 2);39}4041static const struct file_operations led_fops = {42.owner = THIS_MODULE,43.write = led_write,44.read = led_read,45};46static struct miscdevice led_dev = {47.minor = MISC_DYNAMIC_MINOR,48.name = "led", /* → /dev/led */49.fops = &led_fops,50};5152static int __init led_init(void)53{54u32 v;55gpio = ioremap(GPIO_PHYS, GPIO_SIZE);56if (!gpio)57return -ENOMEM;58v = readl(gpio + GPFSEL1); /* GPIO17: bit 23:21 */59v &= ~(7 << 21);60v |= (1 << 21); /* 001 = output */61writel(v, gpio + GPFSEL1);62return misc_register(&led_dev);63}6465static void __exit led_exit(void)66{67misc_deregister(&led_dev);68writel(BIT(LED_PIN), gpio + GPCLR0); /* tắt LED */69writel(readl(gpio + GPFSEL1) & ~(7 << 21), gpio + GPFSEL1);70iounmap(gpio);71}7273module_init(led_init);74module_exit(led_exit);75MODULE_LICENSE("GPL");