| 206 | Pour vous aider, voici un code qui fait clignoter la LED du GPIO04 dans le module noyau. |
| 207 | * Pour l'accès aux GPIOs vous voyez que l'on peut simplifier les calculs d'adresses en utilisant une structure représentant l'organisation des registres. |
| 208 | * Vous noterez également que l'adresse physique de base des GPIO (ici 0x20200000) est mappé dans l'espace virtuel du noyau à l'adresse '''io_addresse'''. |
| 209 | * Vous trouvez aussi le moyen de faire faire périodiquement une fonction au système grâce à une file d'attente temporelle. |
| 210 | Inspirez-vous de code pour votre pilote. |
| 211 | |
| 212 | {{{ |
| 213 | #include <linux/module.h> |
| 214 | #include <linux/init.h> |
| 215 | #include <asm/io.h> |
| 216 | #include <mach/platform.h> |
| 217 | |
| 218 | static const int LED0 = 4; |
| 219 | |
| 220 | //------------------------------------------------------------------------------ |
| 221 | // GPIO ACCES |
| 222 | //------------------------------------------------------------------------------ |
| 223 | |
| 224 | struct gpio_s |
| 225 | { |
| 226 | uint32_t gpfsel[7]; |
| 227 | uint32_t gpset[3]; |
| 228 | uint32_t gpclr[3]; |
| 229 | uint32_t gplev[3]; |
| 230 | uint32_t gpeds[3]; |
| 231 | uint32_t gpren[3]; |
| 232 | uint32_t gpfen[3]; |
| 233 | uint32_t gphen[3]; |
| 234 | uint32_t gplen[3]; |
| 235 | uint32_t gparen[3]; |
| 236 | uint32_t gpafen[3]; |
| 237 | uint32_t gppud[1]; |
| 238 | uint32_t gppudclk[3]; |
| 239 | uint32_t test[1]; |
| 240 | } |
| 241 | *gpio_regs = (struct gpio_s *)__io_address(GPIO_BASE);; |
| 242 | |
| 243 | enum {FUN_INPUT, FUN_OUTPUT}; |
| 244 | |
| 245 | static void gpio_fsel(int pin, int fun) |
| 246 | { |
| 247 | uint32_t reg = pin / 10; |
| 248 | uint32_t bit = (pin % 10) * 3; |
| 249 | uint32_t mask = 0b111 << bit; |
| 250 | gpio_regs->gpfsel[reg] = (gpio_regs->gpfsel[reg] & ~mask) | ((fun << bit) & mask); |
| 251 | } |
| 252 | |
| 253 | static void gpio_write(int pin, bool val) |
| 254 | { |
| 255 | if (val) |
| 256 | gpio_regs->gpset[pin / 32] = (1 << (pin % 32)); |
| 257 | else |
| 258 | gpio_regs->gpclr[pin / 32] = (1 << (pin % 32)); |
| 259 | } |
| 260 | |
| 261 | //------------------------------------------------------------------------------ |
| 262 | // TIMER PROGRAMMING |
| 263 | //------------------------------------------------------------------------------ |
| 264 | |
| 265 | static struct timer_list led_blink_timer; |
| 266 | static int led_blink_period = 1000; |
| 267 | |
| 268 | static void led_blink_handler(unsigned long unused) |
| 269 | { |
| 270 | static bool on = false; |
| 271 | on = !on; |
| 272 | gpio_write(LED0, on); |
| 273 | mod_timer(&led_blink_timer, jiffies + msecs_to_jiffies(led_blink_period)); |
| 274 | } |
| 275 | |
| 276 | //------------------------------------------------------------------------------ |
| 277 | // MODULE INIT & EXIT |
| 278 | //------------------------------------------------------------------------------ |
| 279 | |
| 280 | MODULE_LICENSE("GPL"); |
| 281 | MODULE_AUTHOR("Franck from http://sysprogs.com/VisualKernel/tutorials/raspberry/leddriver/)"); |
| 282 | MODULE_DESCRIPTION("leds on-off"); |
| 283 | |
| 284 | static int __init LedBlinkModule_init(void) |
| 285 | { |
| 286 | int result; |
| 287 | |
| 288 | gpio_fsel(LED0, FUN_OUTPUT); |
| 289 | gpio_write(LED0, 1); |
| 290 | setup_timer(&led_blink_timer, led_blink_handler, 0); |
| 291 | result = mod_timer(&led_blink_timer, jiffies + msecs_to_jiffies(led_blink_period)); |
| 292 | BUG_ON(result < 0); |
| 293 | return 0; |
| 294 | } |
| 295 | |
| 296 | static void __exit LedBlinkModule_exit(void) |
| 297 | { |
| 298 | gpio_fsel(LED0, FUN_INPUT); |
| 299 | del_timer(&led_blink_timer); |
| 300 | } |
| 301 | |
| 302 | module_init(LedBlinkModule_init); |
| 303 | module_exit(LedBlinkModule_exit); |
| 304 | |
| 305 | }}} |