рд▓рд┐рдирдХреНрд╕ рдХрд░реНрдиреЗрд▓ рдореЙрдбреНрдпреВрд▓ рд▓рд┐рдЦрдирд╛: IRIO рд╕рдкреЛрд░реНрдЯ рд╡рд╛рд▓рд╛ GPIO

рд╣реЗрдмреНрд░, рдирдорд╕реНрдХрд╛рд░!

рдпрд╣ рд▓реЗрдЦ рд▓рд┐рдирдХреНрд╕ рдХрд░реНрдиреЗрд▓ рдХреЗ GPIO (рд╕рд╛рдорд╛рдиреНрдп-рдкреНрд░рдпреЛрдЬрди рдЗрдирдкреБрдЯ / рдЖрдЙрдЯрдкреБрдЯ) рдореЙрдбреНрдпреВрд▓ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдХреА рддрд░рд╣, рд╣рдо GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХреА рдмреБрдирд┐рдпрд╛рджреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдЗрдВрдЯрд░рдкреНрдЯ рд╕рдкреЛрд░реНрдЯ (IRQ: Interrupt Request) рдХреЗ рд╕рд╛рде рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВред



рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдХреЗ рд╕рдорд╛рди рд╣реИ: рдирдП рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ GPIO рдмреНрд▓реЙрдХ FPGA рдХреЗ рд▓рд┐рдП "рд╡рд╛рдпрд░реНрдб" рдФрд░ рд▓рд┐рдирдХреНрд╕ рд╕рдВрд╕реНрдХрд░рдг 3.18.19 рдкрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИред

GPIO рдбреНрд░рд╛рдЗрд╡рд░ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдирд┐рдореНрди рдЪрд░рдгреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдирд╛ рд╣реЛрдЧрд╛:

  1. GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдВрддрд░рд┐рдХреНрд╖ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдмреАрдЪ рдмрд╛рддрдЪреАрдд рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрдд рдХреЛ рд╕рдордЭреЗрдВ;
  2. рдЕрд╕реЗрдВрдмрд▓реА рдореЗрдВ рдХрд░реНрдиреЗрд▓ рдореЙрдбреНрдпреВрд▓ рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдбрд┐рд╡рд╛рдЗрд╕ рдЯреНрд░реА рдореЗрдВ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ;
  3. рдЪрд╛рд▓рдХ рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рдХрдВрдХрд╛рд▓, рд╕рд╛рде рд╣реА рдЗрд╕рдХреЗ рдкреНрд░рд╡реЗрд╢ рдФрд░ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐ рдмрд┐рдВрджреБрдУрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ;
  4. GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рднрд╛рдЧ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ;
  5. рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП IRQ рд╕рдорд░реНрдерди рдЬреЛрдбрд╝реЗрдВред

GPIO рдбреНрд░рд╛рдЗрд╡рд░реЛрдВ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдпрд╣рд╛рдВ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ ред

рдкрд╣рд▓рд╛ рдХрджрдо


рдкрд╣рд▓реЗ, рдЪрд▓реЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрдВрд╕реЛрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рдмреАрдЪ рдмрд╛рддрдЪреАрдд рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрдд рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрддреЗ рд╣реИрдВред

рдПрдХ рдЫреЛрдЯреА рдмреИрд╢ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдкреНрд░рддреНрдпреЗрдХ GPIO / sysfs рдХреЗ рд▓рд┐рдП рдирд┐рдпрдВрддреНрд░рдг рдмрдирд╛рдПрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓рд┐рдЦреЗрдВ:

for i in {248..255}; do echo $i > /sys/class/gpio/export; done 

рдЕрдЧрд▓рд╛, рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ GPIO рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рд╕реБрд╡рд┐рдзрд╛рдПрдБ / sysfs рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:

 root@zed-slave:/sys/class/gpio# ls -l gpio248/ total 0 -rw-r--r-- 1 root root 4096 Jan 7 20:50 active_low -rw-r--r-- 1 root root 4096 Jan 7 20:50 direction -rw-r--r-- 1 root root 4096 Jan 7 20:50 edge drwxr-xr-x 2 root root 0 Jan 7 20:50 power lrwxrwxrwx 1 root root 0 Jan 7 20:50 subsystem -> ../../../../class/gpio -rw-r--r-- 1 root root 4096 Jan 7 20:10 uevent -rw-r--r-- 1 root root 4096 Jan 7 20:50 value 

рд╡рд░реНрддрдорд╛рди рдореЗрдВ рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд╖реЗрддреНрд░реЛрдВ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ:

  • рджрд┐рд╢рд╛ - рд░реЗрдЦрд╛ рдХреА рджрд┐рд╢рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреА рд╣реИред рдорд╛рди "рдЗрди" рдпрд╛ "рдЖрдЙрдЯ" рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ;
  • рдореВрд▓реНрдп - рдЖрдкрдХреЛ рд▓рд╛рдЗрди рдкрд░ рдПрдХ рдЙрдЪреНрдЪ рдпрд╛ рдирд┐рдореНрди рд╕рдВрдХреЗрдд рд╕реЗрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (рдпрджрд┐ рджрд┐рд╢рд╛ "рдЖрдЙрдЯ" рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯ рд╣реИ), рдЕрдиреНрдпрдерд╛ (рджрд┐рд╢рд╛ "рдореЗрдВ рд╕реЗрдЯ рд╣реИ") рдЖрдкрдХреЛ рд▓рд╛рдЗрди рдХреА рд╕реНрдерд┐рддрд┐ рдкрдврд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ;
  • рдХрд┐рдирд╛рд░реЗ - рдЖрдкрдХреЛ рдЙрд╕ рдШрдЯрдирд╛ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╡реНрдпрд╡рдзрд╛рди рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИред рдпрд╣ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдорд╛рди рд▓реЗ рд╕рдХрддрд╛ рд╣реИ: "рдХреЛрдИ рдирд╣реАрдВ", "рдЙрдардирд╛", "рдЧрд┐рд░рдирд╛" рдпрд╛ "рджреЛрдиреЛрдВ"ред

Sysfs рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдбреНрд░рд╛рдЗрд╡рд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╕рд╛рде рддреНрд╡рд░рд┐рдд рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк рд╡рд┐рдЪрд╛рд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдбреНрд░рд╛рдЗрд╡рд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрдорд╛рдВрдб рдХреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИред рд▓рд┐рдирдХреНрд╕ рдХрд░реНрдиреЗрд▓ рдореЗрдВ рдПрдХ gpio_chip рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬреЛ gpio рдирд┐рдпрдВрддреНрд░рдХ рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреА рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд╖реЗрддреНрд░ рдЗрд╕рдореЗрдВ рдореМрдЬреВрдж рд╣реИрдВ:

  • direction_input : рдЗрдирдкреБрдЯ рдХреЗ рд▓рд┐рдП рд▓рд╛рдЗрди рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛: ">" рдореЗрдВ /> sys / class / gpio / gpio248 / рджрд┐рд╢рд╛;
  • direction_output : рд▓рд╛рдЗрди рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛: рдЗрдХреЛ "рдЖрдЙрдЯ"> / sys / рд╡рд░реНрдЧ / gpio / gpio248 / рджрд┐рд╢рд╛;
  • get : рдкрдВрдХреНрддрд┐ рдкрд░ рд╕реЗрдЯ рдорд╛рди рдкрдврд╝рддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛: рдмрд┐рд▓реНрд▓реА / рдПрд╕рдЖрдИрдПрд╕ / рд╡рд░реНрдЧ / gpio / gpio248 / value;
  • рд╕реЗрдЯ : рд▓рд╛рдЗрди рдкрд░ рдорд╛рди рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛: рдЗрдХреЛ 1/0> / sys / рд╡рд░реНрдЧ / gpio / gpio248 / value;

рд▓рд┐рдирдХреНрд╕ рдкрд░ IRQ рд╡рд┐рдиреНрдпрд╛рд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ irq_chip рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд╖реЗрддреНрд░ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:

  • irq_set_type : рдИрд╡реЗрдВрдЯ рдХрд╛ рдкреНрд░рдХрд╛рд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╡реНрдпрд╡рдзрд╛рди рдЙрддреНрдкрдиреНрди рд╣реЛрдЧрд╛ред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛: рдЗрдХреЛ> "рд░рд╛рдЗрдЬрд┐рдВрдЧ" / "рдлреЙрд▓рд┐рдВрдЧ" / "рджреЛрдиреЛрдВ"> / sys / рдХреНрд▓рд╛рд╕ / gpio / gpio248 / edge;
  • irq_mask : рдЕрд╡рд░реЛрдз рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛: "рдХреЛрдИ рдирд╣реАрдВ"> / sys / class / gpio / gpio248 / edge;
  • irq_unmask : irq_set_type рдкрд░ рд╕реЗрдЯ рдХреА рдЧрдИ рдИрд╡реЗрдВрдЯ рдкрд░ рд╡реНрдпрд╡рдзрд╛рди рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рддрд╛ рд╣реИред Irq_set_type рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рджреВрд╕рд░рд╛ рдХрджрдо


рдЕрдм рдЖрдк рдбреНрд░рд╛рдЗрд╡рд░ рдХреЛ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдореЗрдВ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдорд╛рдирдХ рдЪрд░рдгреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреЗ рд╣реБрдП рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╕реНрд░реЛрдд рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ:

 cd drivers/gpio/ vim gpio-skel.c :wq 

рд╣рдо рдбреНрд░рд╛рдЗрд╡рд░ / gpio / Kconfig рдореЗрдВ рдбреНрд░рд╛рдЗрд╡рд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ :

 config GPIO_SKEL tristate "SKEL GPIO" help Say yes here to support SKEL GPIO. 

рдбреНрд░рд╛рдЗрд╡рд░ / рдЕрд╕реЗрдВрдмрд▓реА / рдореЗрдХрдлрд╛рдЗрд▓ рдореЗрдВ рдбреНрд░рд╛рдЗрд╡рд░ рдХреЛ рдЕрд╕реЗрдВрдмрд▓реА рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:

 obj-$(CONFIG_GPIO_SKEL) += gpio-skel.o 

рдФрд░ рдЕрдВрдд рдореЗрдВ, devicetree рдХреЛ GPIO рдмреНрд▓реЙрдХ рдХрд╛ рд╡рд┐рд╡рд░рдг рдЬреЛрдбрд╝реЗрдВ (* .dts):

 gpio: gpio@f8f01d00 { compatible = "skel-gpio"; rcm,ngpio = <8>; rcm,interrupt-type = <IRQ_TYPE_EDGE_RISING>; clocks = <&clkc 42>; gpio-controller ; interrupt-parent = <&ps7_scugic_0>; interrupts = <0 29 4>; reg = <0x43c00000 0x100>; } ; 

рдЖрдк рдпрд╣рд╛рдВ рджреЗрд╡реАрдЪрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред

рдЪрд░рдг рддреАрди


рдЪрд▓реЛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рднрд╛рдЧ рдкрд░ рдЪрд▓рддреЗ рд╣реИрдВ!

рд╣рдо рдЖрд╡рд╢реНрдпрдХ рд╣реЗрдбрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдЬреЛрдбрд╝рдХрд░ рдФрд░ IRQ рд╕рдорд░реНрдерди рдХреЗ рдмрд┐рдирд╛ рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рдкреВрд░реНрдг рдХрдВрдХрд╛рд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдХреЗ рдЪрд╛рд▓рдХ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред рдЕрдЧрд▓рд╛, рд╣рдо рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдПрдХ рдХреЛрдб рдХреЗ рд╕рд╛рде рднрд░реЗрдВрдЧреЗ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд╕рд╛рде рдХрд░реЗрдВрдЧреЗред

GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХрдВрдХрд╛рд▓
 /* gpio-skel.c: GPIO driver * * Name Surname <email> * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ #include <linux/of.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/irqdomain.h> #include <linux/bitops.h> #include <linux/irqchip/chained_irq.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/gpio/driver.h> #include <linux/platform_device.h> #define SKEL_GPIO_VER 0x04 #define SKEL_GPIO_PAD_DIR 0x08 #define SKEL_GPIO_WR_DATA 0x0C #define SKEL_GPIO_RD_DATA 0x10 #define SKEL_GPIO_WR_DATA1 0x1C #define SKEL_GPIO_WR_DATA0 0x20 #define SKEL_GPIO_SRC 0x24 #define SKEL_GPIO_MAX_NGPIO 8 #define GPIO_OFFSET 4 struct skel_gpio_chip { struct gpio_chip gchip; spinlock_t lock; void __iomem *regs; u32 type; }; static inline void gpio_write(uint32_t value, void *base, uint32_t addr) { writel(value, base + addr); #if defined DEBUG dev_dbg(rdev->dev, "iowrite32(0x%x, base + 0x%x);\n", value, addr); #endif } static inline uint32_t gpio_read(void *base, uint32_t addr) { uint32_t reg = readl(base + addr); #if defined DEBUG dev_dbg(rdev->dev, "/* ioread32(base + 0x%x) == 0x%x */\n", addr, reg); #endif return reg; } static inline struct skel_gpio_chip *to_skel_gpio(struct gpio_chip *chip) { } /* * echo "in" > /sys/class/gpio/gpioN/direction */ static int skel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { } /* * echo "out" > /sys/class/gpio/gpioN/direction */ static int skel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { } static int skel_gpio_get(struct gpio_chip *chip, unsigned offset) { } static void skel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { } static int skel_gpio_probe(struct platform_device *pdev) { } static int skel_gpio_remove(struct platform_device *pdev) { } static const struct of_device_id skel_gpio_of_match[] = { { .compatible = "skel-gpio" }, { }, }; MODULE_DEVICE_TABLE(of, skel_gpio_of_match); static struct platform_driver skel_gpio_driver = { .probe = skel_gpio_probe, .remove = skel_gpio_remove, .driver = { .name = "skel-gpio", .of_match_table = of_match_ptr(skel_gpio_of_match), }, }; module_platform_driver(skel_gpio_driver); MODULE_DESCRIPTION("GPIO driver"); MODULE_AUTHOR("Name Surname"); MODULE_LICENSE("GPL"); 


рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛ рдХрдВрдХрд╛рд▓ рдХрд╛рдлреА рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдХрдИ рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдп рдФрд░ рд╕рдВрд░рдЪрдирд╛рдПрдВ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИрдВред

рднрд╡рд┐рд╖реНрдп рдХреЗ рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддрддреНрд╡реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  • platform_driver skel_gpio_driver - рдХрд░реНрдиреЗрд▓ рд╕реЗ рдирд┐рдХрд╛рд▓реЗ рдЬрд╛рдиреЗ рдкрд░ рдбреНрд░рд╛рдЗрд╡рд░ рдФрд░ skel_gpio_remove рд▓реЛрдб рдХрд░рддреЗ рд╕рдордп рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ skel_gpio_probe рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ;
  • рд╕рдВрд░рдЪрдирд╛ of_device_id skel_gpio_of_match - рдЗрд╕рдореЗрдВ рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рд╣реИ рдЬреЛ GPIO рдмреНрд▓реЙрдХ рдХреЗ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреА рд╣реИ;
  • рд╕рдВрд░рдЪрдирд╛ skel_gpio_chip - GPIO рдмреНрд▓реЙрдХ рдбреНрд░рд╛рдЗрд╡рд░ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рд╣реИрдВред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд▓рд┐рдирдХреНрд╕ рд╕реЗ / рдХреЗ рд▓рд┐рдП рдбреНрд░рд╛рдЗрд╡рд░ рдХреЛ рд▓реЛрдб / рдПрдХреНрд╕рдЯреНрд░реИрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, .probe рдФрд░ .remove рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ skel_gpio_driver рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред

Skel_gpio_probe рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 static int skel_gpio_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct skel_gpio_chip *skel_gc; struct resource *res; int ngpio, ret; skel_gc = devm_kzalloc(&pdev->dev, sizeof(*skel_gc), GFP_KERNEL); if (!skel_gc) return -ENOMEM; spin_lock_init(&skel_gc->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get MMIO resource for GPIO.\n"); return -EINVAL; } skel_gc->regs = devm_ioremap_resource(&pdev->dev, res); if (!skel_gc->regs) goto free; if (!of_property_read_u32(node, "skel,ngpio", &ngpio)) skel_gc->gchip.ngpio = ngpio; else skel_gc->gchip.ngpio = SKEL_GPIO_MAX_NGPIO; if (skel_gc->gchip.ngpio > SKEL_GPIO_MAX_NGPIO) { dev_warn(&pdev->dev, "Number of gpio is greater than MAX!\n"); skel_gc->gchip.ngpio = SKEL_GPIO_MAX_NGPIO; } skel_gc->gchip.direction_input = skel_gpio_direction_input; skel_gc->gchip.direction_output = skel_gpio_direction_output; skel_gc->gchip.get = skel_gpio_get; skel_gc->gchip.set = skel_gpio_set; skel_gc->gchip.owner = THIS_MODULE; skel_gc->gchip.base = -1; platform_set_drvdata(pdev, skel_gc); ret = gpiochip_add(&skel_gc->gchip); if (ret) { dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); return ret; } dev_info(&pdev->dev, "SKEL GPIO probe complete: (%d .. %d)\n", skel_gc->gchip.base, skel_gc->gchip.base + skel_gc->gchip.ngpio); return 0; } 


Skel_gpio_remove рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 static int skel_gpio_remove(struct platform_device *pdev) { struct skel_gpio_chip *skel_gc = platform_get_drvdata(pdev); gpiochip_remove(&skel_gc->gchip); return 0; } 


Skel_gpio_remove рдлрд╝рдВрдХреНрд╢рди рдХреЗрд╡рд▓ рдкрдВрдЬреАрдХреГрдд GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХреЛ рдХрд░реНрдиреЗрд▓ рд╕реЗ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП skel_gpio_probe рдореЗрдВ рдореБрдЦреНрдп рдмрд┐рдВрджреБрдУрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:

  • devm_kzalloc - skel_gpio_chip рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рддрд╛ рд╣реИ;
  • platform_get_resource - devicetree рд╕реЗ GPIO рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд╛рд░реНрдб рдХреА рд╢реБрд░реБрдЖрдд рдХрд╛ рдкрддрд╛ рдкрдврд╝рддрд╛ рд╣реИ;
  • devm_ioremap_resource - рднреМрддрд┐рдХ рдкрддреЗ рдХреА рдореИрдкрд┐рдВрдЧ рдПрдХ рд╡рд░реНрдЪреБрдЕрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реИ;
  • of_property_read_u32 - devicetree рд╕реЗ рдЙрдкрд▓рдмреНрдз GPIO рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ;
  • skel_gc-> gchipред * - рдЖрд╡рд╢реНрдпрдХ рд╕рдВрд░рдЪрдирд╛ рдХреНрд╖реЗрддреНрд░реЛрдВ рдореЗрдВ рднрд░рддрд╛ рд╣реИ;
  • gpiochip_add - рдбреНрд░рд╛рдЗрд╡рд░ рдореЗрдВ рдПрдХ GPIO рдирд┐рдпрдВрддреНрд░рдХ рдЬреЛрдбрд╝рддрд╛ рд╣реИ;

рдЕрдм рддрдХ, рдпрд╣ рд╡рд░реНрдгрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ 248 ... 255 рдЬреИрд╕реА рдЬрд╛рджреБрдИ рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ skel_gc-> gchip.base = -1; рдХрд░реНрдиреЗрд▓ рдХреЛ GPIO рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдирдВрдмрд░реЛрдВ рдХреЛ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реИред рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рдЕрдВрдд рдореЗрдВ рдЗрди рдирдВрдмрд░реЛрдВ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдЙрдЯрдкреБрдЯ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ:

 dev_info(&pdev->dev, "SKEL GPIO probe complete: (%d .. %d)\n", skel_gc->gchip.base, skel_gc->gchip.base + skel_gc->gchip.ngpio); 

рдмреЗрд╢рдХ, рд▓рд┐рдирдХреНрд╕ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕реНрд░реЛрдд рдХреЛрдб рдореЗрдВ рдЯрд┐рдкреНрдкрдгреА рдХреЛ рджреЗрдЦреЗрдВ:

 @base: identifies the first GPIO number handled by this chip; * or, if negative during registration, requests dynamic ID allocation. * DEPRECATION: providing anything non-negative and nailing the base * offset of GPIO chips is deprecated. Please pass -1 as base to * let gpiolib select the chip base in all possible cases. We want to * get rid of the static GPIO number space in the long run. 


рдЪреМрдерд╛ рдЪрд░рдг


рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рднрд╛рдЧ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ, рдЕрд░реНрдерд╛рддреН, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:
.direction_output , .direction_input , .get рдФрд░ .set ред рдЕрдЧрд▓рд╛, рдПрдХ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░-рдирд┐рд░реНрднрд░ рдХреЛрдб рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬреЛ рдХрд┐ рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЕрд▓рдЧ рд╣реЛрдЧрд╛ред

Skel_gpio_direction_input рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 /* * echo "in" > /sys/class/gpio/gpioN/direction */ static int skel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { struct skel_gpio_chip *gc = to_skel_gpio(chip); unsigned long flag; u32 data_dir; spin_lock_irqsave(&gc->lock, flag); data_dir = gpio_read(gc->regs, SKEL_GPIO_PAD_DIR); data_dir &= ~BIT(offset); gpio_write(data_dir, gc->regs, SKEL_GPIO_PAD_DIR); spin_unlock_irqrestore(&gc->lock, flag); return 0; } 


Skel_gpio_direction_input рд╡рд┐рдзрд┐ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░рддреА рд╣реИ:

  • рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрдорд╛рдВрдб рдЗрдХреЛ рдХреЗ рд╕рд╛рде "> / sys / class / gpio / gpioN / рджрд┐рд╢рд╛ рдореЗрдВ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ;
  • рд░рдЬрд┐рд╕реНрдЯрд░ SKEL_GPIO_PAD_DIR рдкрдврд╝рддрд╛ рд╣реИ, рдЬреЛ GPIO рдкрд┐рди рдХреА рджрд┐рд╢рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ;
  • рдЖрд╡рд╢реНрдпрдХ рдореБрдЦреМрдЯрд╛ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ;
  • рдкреНрд░рд╛рдкреНрдд рдорд╛рди рдХреЛ SKEL_GPIO_PAD_DIR рдкрд░ рд╡рд╛рдкрд╕ рд▓рд┐рдЦрддрд╛ рд╣реИред

Skel_gpio_direction_output рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 /* * echo "out" > /sys/class/gpio/gpioN/direction */ static int skel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct skel_gpio_chip *gc = to_skel_gpio(chip); unsigned long flag; u32 data_reg, data_dir; spin_lock_irqsave(&gc->lock, flag); data_reg = gpio_read(gc->regs, SKEL_GPIO_WR_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); gpio_write(data_reg, gc->regs, SKEL_GPIO_WR_DATA); data_dir = gpio_read(gc->regs, SKEL_GPIO_PAD_DIR); data_dir |= BIT(offset); gpio_write(data_dir, gc->regs, SKEL_GPIO_PAD_DIR); spin_unlock_irqrestore(&gc->lock, flag); return 0; } 


Skel_gpio_direction_output рд╡рд┐рдзрд┐ skel_gpio_direction_inut рдХреЗ рд╕рдорд╛рди рдХрд╛рд░реНрдп рдХрд░рддреА рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЗрд╕реЗ рдирд┐рдореНрди рдЖрджреЗрд╢реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ:

  • рдЗрдХреЛ "рдЖрдЙрдЯ"> / sys / рд╡рд░реНрдЧ / gpio / gpioN / рджрд┐рд╢рд╛;
  • рдЗрдХреЛ "рдЙрдЪреНрдЪ"> / sys / рд╡рд░реНрдЧ / gpio / gpioN / рджрд┐рд╢рд╛, рдорд╛рди рдХреЛ 1 рдкрд░ рд╕реЗрдЯ рдХрд░рдирд╛;
  • рдЗрдХреЛ "рдХрдо"> / sys / рд╡рд░реНрдЧ / gpio / gpioN / рджрд┐рд╢рд╛, рдорд╛рди рдХреЛ 0 рдкрд░ рд╕реЗрдЯ рдХрд░рдирд╛ред

рдореВрд▓реНрдп - рдПрдХ рдорд╛рди рдЬреЛ рдЖрдЙрдЯрдкреБрдЯ рд▓рд╛рдЗрди рдкрд░ рд╕рд┐рдЧреНрдирд▓ рд╕реНрддрд░ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИред

Skel_gpio_set рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 static void skel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct skel_gpio_chip *gc = to_skel_gpio(chip); unsigned long flag; unsigned int data_reg; spin_lock_irqsave(&gc->lock, flag); data_reg = gpio_read(gc->regs, SKEL_GPIO_WR_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); gpio_write(data_reg, gc->regs, SKEL_GPIO_WR_DATA); spin_unlock_irqrestore(&gc->lock, flag); } 


Skel_gpio_set рд╡рд┐рдзрд┐ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░рддреА рд╣реИ:

  • рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрдорд╛рдВрдб рдЗрдХреЛ 1/0> / sys / class / gpio / gpioN / value рдХреЗ рд╕рд╛рде рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ;
  • рд░реАрдб рд░рдЬрд┐рд╕реНрдЯрд░ SKEL_GPIO_WR_DATA, рдЬреЛ рд▓рд╛рдЗрди рдкрд░ рд╡рд░реНрддрдорд╛рди рд╕рд┐рдЧреНрдирд▓ рдХрд╛ рдореВрд▓реНрдп рджрд┐рдЦрд╛рддрд╛ рд╣реИ;
  • рдСрдлрд╕реЗрдЯ рджреНрд╡рд╛рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рдмрд┐рдЯ рд╕реЗрдЯ рдпрд╛ рд░реАрд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ;
  • рдкреНрд░рд╛рдкреНрдд рдорд╛рди рдХреЛ SKEL_GPIO_WR_DATA рдореЗрдВ рд╡рд╛рдкрд╕ рд▓рд┐рдЦрддрд╛ рд╣реИред

Skel_gpio_get рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 static int skel_gpio_get(struct gpio_chip *chip, unsigned offset) { struct skel_gpio_chip *gc = to_skel_gpio(chip); return !!(gpio_read(gc->regs, SKEL_GPIO_RD_DATA) & BIT(offset)); } 


Skel_gpio_get рд╡рд┐рдзрд┐ рдХреЛрдб SKEL_GPIO_RD_DATA рдХреЛ рдкрдврд╝рдХрд░ рд▓рд╛рдЗрди рдкрд░ рд╕рд┐рдЧреНрдирд▓ рдорд╛рди рдХреЛ рдкрдврд╝рддреА рд╣реИред

рд╣рдордиреЗ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд╡рд┐рдзрд┐рдпреЛрдВ рдФрд░ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк рд╕рдм рдХреБрдЫ рдПрдХ рд╕рд╛рде рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЕрдВрддрд┐рдо рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВред

GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 /* gpio-skel.c: GPIO driver * * Name Surname <email> * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ #include <linux/of.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/irqdomain.h> #include <linux/bitops.h> #include <linux/irqchip/chained_irq.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/gpio/driver.h> #include <linux/platform_device.h> #define SKEL_GPIO_VER 0x04 #define SKEL_GPIO_PAD_DIR 0x08 #define SKEL_GPIO_WR_DATA 0x0C #define SKEL_GPIO_RD_DATA 0x10 #define SKEL_GPIO_WR_DATA1 0x1C #define SKEL_GPIO_WR_DATA0 0x20 #define SKEL_GPIO_SRC 0x24 #define SKEL_GPIO_MAX_NGPIO 8 #define GPIO_OFFSET 4 struct skel_gpio_chip { struct gpio_chip gchip; spinlock_t lock; void __iomem *regs; u32 type; }; static inline void gpio_write(uint32_t value, void *base, uint32_t addr) { writel(value, base + addr); #if defined DEBUG dev_dbg(rdev->dev, "iowrite32(0x%x, base + 0x%x);\n", value, addr); #endif } static inline uint32_t gpio_read(void *base, uint32_t addr) { uint32_t reg = readl(base + addr); #if defined DEBUG dev_dbg(rdev->dev, "/* ioread32(base + 0x%x) == 0x%x */\n", addr, reg); #endif return reg; } static inline struct skel_gpio_chip *to_skel_gpio(struct gpio_chip *chip) { return container_of(chip, struct skel_gpio_chip, gchip); } /* * echo > "out" > /sys/class/gpio/gpioN/direction */ static int skel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct skel_gpio_chip *gc = to_skel_gpio(chip); unsigned long flag; u32 data_reg, data_dir; spin_lock_irqsave(&gc->lock, flag); data_reg = gpio_read(gc->regs, SKEL_GPIO_WR_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); gpio_write(data_reg, gc->regs, SKEL_GPIO_WR_DATA); data_dir = gpio_read(gc->regs, SKEL_GPIO_PAD_DIR); data_dir |= BIT(offset); gpio_write(data_dir, gc->regs, SKEL_GPIO_PAD_DIR); spin_unlock_irqrestore(&gc->lock, flag); return 0; } /* * echo > "in" > /sys/class/gpio/gpioN/direction */ static int skel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { struct skel_gpio_chip *gc = to_skel_gpio(chip); unsigned long flag; u32 data_dir; spin_lock_irqsave(&gc->lock, flag); data_dir = gpio_read(gc->regs, SKEL_GPIO_PAD_DIR); data_dir &= ~BIT(offset); gpio_write(data_dir, gc->regs, SKEL_GPIO_PAD_DIR); spin_unlock_irqrestore(&gc->lock, flag); return 0; } static int skel_gpio_get(struct gpio_chip *chip, unsigned offset) { struct skel_gpio_chip *gc = to_skel_gpio(chip); return !!(gpio_read(gc->regs, SKEL_GPIO_RD_DATA) & BIT(offset)); } static void skel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct skel_gpio_chip *gc = to_skel_gpio(chip); unsigned long flag; unsigned int data_reg; spin_lock_irqsave(&gc->lock, flag); data_reg = gpio_read(gc->regs, SKEL_GPIO_WR_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); gpio_write(data_reg, gc->regs, SKEL_GPIO_WR_DATA); spin_unlock_irqrestore(&gc->lock, flag); } static int skel_gpio_remove(struct platform_device *pdev) { struct skel_gpio_chip *skel_gc = platform_get_drvdata(pdev); gpiochip_remove(&skel_gc->gchip); return 0; } static int skel_gpio_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct skel_gpio_chip *skel_gc; struct resource *res; int ngpio, ret; skel_gc = devm_kzalloc(&pdev->dev, sizeof(*skel_gc), GFP_KERNEL); if (!skel_gc) return -ENOMEM; spin_lock_init(&skel_gc->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get MMIO resource for GPIO.\n"); return -EINVAL; } skel_gc->regs = devm_ioremap_resource(&pdev->dev, res); if (!skel_gc->regs) return -ENXIO; if (!of_property_read_u32(node, "skel,ngpio", &ngpio)) skel_gc->gchip.ngpio = ngpio; else skel_gc->gchip.ngpio = SKEL_GPIO_MAX_NGPIO; if (skel_gc->gchip.ngpio > SKEL_GPIO_MAX_NGPIO) { dev_warn(&pdev->dev, "Number of gpio is greater than MAX!\n"); skel_gc->gchip.ngpio = SKEL_GPIO_MAX_NGPIO; } skel_gc->gchip.direction_input = skel_gpio_direction_input; skel_gc->gchip.direction_output = skel_gpio_direction_output; skel_gc->gchip.get = skel_gpio_get; skel_gc->gchip.set = skel_gpio_set; skel_gc->gchip.owner = THIS_MODULE; skel_gc->gchip.base = -1; platform_set_drvdata(pdev, skel_gc); ret = gpiochip_add(&skel_gc->gchip); if (ret) { dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); return ret; } dev_info(&pdev->dev, "SKEL GPIO probe complete: (%d .. %d)\n", skel_gc->gchip.base, skel_gc->gchip.base + skel_gc->gchip.ngpio); return 0; } static const struct of_device_id skel_gpio_of_match[] = { { .compatible = "skel-gpio" }, { }, }; MODULE_DEVICE_TABLE(of, skel_gpio_of_match); static struct platform_driver skel_gpio_driver = { .probe = skel_gpio_probe, .remove = skel_gpio_remove, .driver = { .name = "skel-gpio", .of_match_table = of_match_ptr(skel_gpio_of_match), }, }; module_platform_driver(skel_gpio_driver); MODULE_DESCRIPTION("GPIO driver"); MODULE_AUTHOR("Name Surname"); MODULE_LICENSE("GPL"); 


рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдбреНрд░рд╛рдЗрд╡рд░ рдореЗрдВ GPIO рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд▓рд╣рд╛рд▓ рдбреНрд░рд╛рдЗрд╡рд░ рдмрд╛рдзрд╛ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдк рдЕрдЧрд▓реЗ рдЪрд░рдг рдкрд░ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред

рдкрд╛рдВрдЪрд╡рд╛рдВ рдЪрд░рдг


GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдореЗрдВ IRQ рдЬреЛрдбрд╝рдиреЗ рдХреЛ рддреАрди рдЪрд░рдгреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

  • рдЧрд┐рд░реА рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдореЗрдВ рд╕рдорд░реНрдерд┐рдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рд╡рд┐рд╡рд░рдг;
  • рдЬрд┐рд╕ рд╕рдордп рдбреНрд░рд╛рдЗрд╡рд░ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рд▓реЛрдб рд╣реЛрддрд╛ рд╣реИ рдЙрд╕ рд╕рдордп IRQ рд╕рдкреЛрд░реНрдЯ рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рдирд╛;
  • рд╕рдорд░реНрдерд┐рдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред

рдкреНрд░рд╛рд░рдВрдн рдореЗрдВ, рд╣рдо рд╕рдВрдЪрд╛рд▓рди рдХреЗ рдЖрд╡рд╢реНрдпрдХ рд╕реЗрдЯ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ:

 static struct irq_chip skel_irq_chip = { .name = "skel-gpio", .irq_mask = skel_gpio_irq_mask, .irq_unmask = skel_gpio_irq_unmask, .irq_set_type = skel_gpio_irq_set_type, }; 

рдЗрд╕рд▓рд┐рдП, рдбреНрд░рд╛рдЗрд╡рд░ (skel_gpio_irq_unmask) / рдЕрдХреНрд╖рдо (skel_gpio_irq_mask) рд░реБрдХрд╛рд╡рдЯреЛрдВ рдХреЛ рд╕рдХреНрд╖рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдШрдЯрдирд╛ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдпрд╣ рдЙрддреНрдкрдиреНрди рд╣реЛрдЧрд╛ (skel_gpio_irq_set_type)ред
рдЕрдЧрд▓рд╛, рд╣рдо рдХреЗрд╡рд▓ рдЙрд╕ рд╡рд┐рдзрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдПрдХ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрднрд╛рд╕реА irq рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдореИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред

 static struct irq_domain_ops skel_gpio_irq_domain_ops = { .map = skel_gpio_irq_domain_map, }; 

рдлрд┐рд░ рд╣рдо рдХрд░реНрдиреЗрд▓ рдХреЛ рдмрддрд╛рдПрдВрдЧреЗ рдХрд┐ рд▓реЛрдб рдХрд┐рдП рдЧрдП рдбреНрд░рд╛рдЗрд╡рд░ IRQ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЬрд╛рдБрдЪ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдирд┐рдореНрди рдХреЛрдб рдЬреЛрдбрд╝реЗрдВ:

IRQ рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рдирд╛
 skel_gc->gchip.to_irq = skel_gpio_to_irq; skel_gc->domain = irq_domain_add_linear(pdev->dev.of_node, rcm_gc->gchip.ngpio, &skel_gpio_irq_domain_ops, skel_gc); if (!skel_gc->domain) return -ENODEV; skel_gc->irq = platform_get_irq(pdev, 0); if (skel_gc->irq < 0) goto free; for (i = 0; i < skel_gc->gchip.ngpio; i++) { int irq = rcm_gpio_to_irq(&skel_gc->gchip, i); irq_set_chip_and_handler(irq, &skel_irq_chip, handle_simple_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else irq_set_noprobe(irq); #endif } irq_set_chained_handler(skel_gc->irq, skel_irq_handler); irq_set_handler_data(skel_gc->irq, skel_gc); 


рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ рд╣реЛрддрд╛ рд╣реИ:

  • Irq_domain рдХреЗ рддрд╣рдд рдХреНрд╖реЗрддреНрд░ рдХрд╛ рдЖрд╡рдВрдЯрди рдФрд░ рдЖрд░рдВрднреАрдХрд░рдг;
  • рд╡рд┐рдЪрд▓рди рдХреЗ рд╕рд╛рде рд╡реНрдпрд╡рдзрд╛рди рд╕рдВрдЦреНрдпрд╛ рдкрдврд╝реЗрдВ;
  • рд╡рд░реНрдЪреБрдЕрд▓ рдФрд░ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рд╡реНрдпрд╡рдзрд╛рди рдХреЗ рдмреАрдЪ рдореИрдкрд┐рдВрдЧ;
  • рдПрдХ рдмрд╛рдзрд╛ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рдФрд░ рд╣реИрдВрдбрд▓рд░ рдХреЛ рд╕рдВрдЪрд░рдг рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХрд░рдирд╛;

рд╣рдо рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдХреБрдЫ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред
skel_gpio_to_irq - рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдФрд░ рд╡рд░реНрдЪреБрдЕрд▓ рдЗрдВрдЯрд░рдкреНрдЯ рдХреЗ рдмреАрдЪ рдореИрдкрд┐рдВрдЧ рдмрдирд╛рддрд╛ рд╣реИред рдпрджрд┐ рдпрд╣ рдорд╛рдирдЪрд┐рддреНрд░рдг рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдпрд╣ рдмрдирд╛рдП рдЧрдП рд╡рд░реНрдЪреБрдЕрд▓ рдЗрдВрдЯрд░рдкреНрдЯ рдХреА рд╕рдВрдЦреНрдпрд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИред

Skel_gpio_to_irq рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 static int skel_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { struct skel_gpio_chip *rcm = to_skel_gpio(chip); return irq_create_mapping(rcm->domain, gpio); } 


skel_irq_handler рдПрдХ рдмрд╛рдзрд╛ рд╣реИрдВрдбрд▓рд░ рд╣реИ:

  • рдПрдХ рдмрд╛рдзрд╛ рд╕реНрдерд┐рддрд┐ рд░рдЬрд┐рд╕реНрдЯрд░ рдкрдврд╝рддрд╛ рд╣реИ;
  • рд░реБрдХрд╛рд╡рдЯ рдореБрдЦреМрдЯрд╛ рд░рдЬрд┐рд╕реНрдЯрд░ рдкрдврд╝рддрд╛ рд╣реИ;
  • рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдореЗрдВ рдереНрд░реЛ рдмрд╛рдзрд┐рдд рд╣реЛрддрд╛ рд╣реИ;
  • рдкреНрд░рддреНрдпреЗрдХ GPIO рдХреЗ рд▓рд┐рдП рдЬрд┐рд╕рдореЗрдВ рдПрдХ рд╡реНрдпрд╡рдзрд╛рди рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИ, рдЬреЗрдиреЗрд░рд┐рдХ_рд╣реИрдВрдбрд▓_рдХрд┐рд░ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред

рдмрд╛рдзрд╛ рд╣реИрдВрдбрд▓рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
 static void skel_irq_handler(unsigned int irq, struct irq_desc *desc) { struct skel_gpio_chip *skel_gc = irq_get_handler_data(irq); struct irq_chip *chip = irq_desc_get_chip(desc); void __iomem *base; u32 status, mask, gpio, pending; chained_irq_enter(chip, desc); base = skel_gc->regs; status = gpio_read(base, SKEL_GPIO_STATUS); mask = gpio_read(base, SKEL_GPIO_IRQ_MASK); pending = status & mask; while (pending) { gpio = __ffs(pending); pending &= ~BIT(gpio); generic_handle_irq( irq_find_mapping(skel_gc->domain, gpio)); } chained_irq_exit(chip, desc); } 


рдмрд╕ рдЗрддрдирд╛ рд╣реА, рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╣рдордиреЗ рд╕реАрдЦрд╛ рдХрд┐ рдХреИрд╕реЗ GPIO рдбреНрд░рд╛рдЗрд╡рд░ sysfs рд╡рд░реНрдЪреБрдЕрд▓ рдлрд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рд╛рде рдЗрдВрдЯрд░реИрдХреНрдЯ рдХрд░рддрд╛ рд╣реИ, GPIO рдбреНрд░рд╛рдЗрд╡рд░ рдХреЗ рдореВрд▓ рдврд╛рдВрдЪреЗ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ IRQ рдХреЛ рд╕рдкреЛрд░реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рддрд░реАрдХреЛрдВ рдХреА рднреА рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИред

рд▓реЗрдЦ рдореЗрдВ рджреЛ рдХрд╛рд░рдгреЛрдВ рд╕реЗ skel_gpio_irq_unmask, skel_gpio_irq_mask, рдФрд░ skel_gpio_irq_set_type рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рд╡рд░реНрдгрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИред рджреВрд╕рд░реЗ, рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдкрд░ рдирд┐рд░реНрднрд░ред рд╡реЗ GPIO рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рд╡рд╛рд▓реА рдХреБрдЫ рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрд╡рдзрд╛рди рдХреА рдЕрдиреБрдорддрд┐ рдпрд╛ рдЕрдХреНрд╖рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред

рдХреГрдкрдпрд╛, рдпрджрд┐ рдЖрдкрдХреЛ рддреНрд░реБрдЯрд┐рдпрд╛рдВ / рдЧрд▓рддрд┐рдпрд╛рдБ рдорд┐рд▓рддреА рд╣реИрдВ, рдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╣реИ, рддреЛ рдкреАрдПрдо рдпрд╛ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рд▓рд┐рдЦреЗрдВред

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

Source: https://habr.com/ru/post/hi419273/


All Articles