| | 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 | }}} |