fb82edb21b30afe144f9de094bfb0193fa4799bb
[librecmc/librecmc.git] / target / linux / generic / pending-4.14 / 834-ledtrig-libata.patch
1 From: Daniel Golle <daniel@makrotopia.org>
2 Subject: libata: add ledtrig support
3
4 This adds a LED trigger for each ATA port indicating disk activity.
5
6 As this is needed only on specific platforms (NAS SoCs and such),
7 these platforms should define ARCH_WANTS_LIBATA_LEDS if there
8 are boards with LED(s) intended to indicate ATA disk activity and
9 need the OS to take care of that.
10 In that way, if not selected, LED trigger support not will be
11 included in libata-core and both, codepaths and structures remain
12 untouched.
13
14 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
15 ---
16  drivers/ata/Kconfig       | 16 ++++++++++++++++
17  drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
18  include/linux/libata.h    |  9 +++++++++
19  3 files changed, 66 insertions(+)
20
21 --- a/drivers/ata/Kconfig
22 +++ b/drivers/ata/Kconfig
23 @@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
24  
25           If unsure, say Y.
26  
27 +config ARCH_WANT_LIBATA_LEDS
28 +       bool
29 +
30 +config ATA_LEDS
31 +       bool "support ATA port LED triggers"
32 +       depends on ARCH_WANT_LIBATA_LEDS
33 +       select NEW_LEDS
34 +       select LEDS_CLASS
35 +       select LEDS_TRIGGERS
36 +       default y
37 +       help
38 +         This option adds a LED trigger for each registered ATA port.
39 +         It is used to drive disk activity leds connected via GPIO.
40 +
41 +         If unsure, say N.
42 +
43  config ATA_ACPI
44         bool "ATA ACPI Support"
45         depends on ACPI
46 --- a/drivers/ata/libata-core.c
47 +++ b/drivers/ata/libata-core.c
48 @@ -730,6 +730,19 @@ u64 ata_tf_read_block(const struct ata_t
49         return block;
50  }
51  
52 +#ifdef CONFIG_ATA_LEDS
53 +#define LIBATA_BLINK_DELAY 20 /* ms */
54 +static inline void ata_led_act(struct ata_port *ap)
55 +{
56 +       unsigned long led_delay = LIBATA_BLINK_DELAY;
57 +
58 +       if (unlikely(!ap->ledtrig))
59 +               return;
60 +
61 +       led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
62 +}
63 +#endif
64 +
65  /**
66   *     ata_build_rw_tf - Build ATA taskfile for given read/write request
67   *     @tf: Target ATA taskfile
68 @@ -5160,6 +5173,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
69                 if (tag < 0)
70                         return NULL;
71         }
72 +#ifdef CONFIG_ATA_LEDS
73 +       ata_led_act(ap);
74 +#endif
75  
76         qc = __ata_qc_from_tag(ap, tag);
77         qc->tag = tag;
78 @@ -6063,6 +6079,9 @@ struct ata_port *ata_port_alloc(struct a
79         ap->stats.unhandled_irq = 1;
80         ap->stats.idle_irq = 1;
81  #endif
82 +#ifdef CONFIG_ATA_LEDS
83 +       ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
84 +#endif
85         ata_sff_port_init(ap);
86  
87         return ap;
88 @@ -6084,6 +6103,12 @@ static void ata_host_release(struct devi
89  
90                 kfree(ap->pmp_link);
91                 kfree(ap->slave_link);
92 +#ifdef CONFIG_ATA_LEDS
93 +               if (ap->ledtrig) {
94 +                       led_trigger_unregister(ap->ledtrig);
95 +                       kfree(ap->ledtrig);
96 +               };
97 +#endif
98                 kfree(ap);
99                 host->ports[i] = NULL;
100         }
101 @@ -6530,7 +6555,23 @@ int ata_host_register(struct ata_host *h
102                 host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
103                 host->ports[i]->local_port_no = i + 1;
104         }
105 +#ifdef CONFIG_ATA_LEDS
106 +       for (i = 0; i < host->n_ports; i++) {
107 +               if (unlikely(!host->ports[i]->ledtrig))
108 +                       continue;
109  
110 +               snprintf(host->ports[i]->ledtrig_name,
111 +                       sizeof(host->ports[i]->ledtrig_name), "ata%u",
112 +                       host->ports[i]->print_id);
113 +
114 +               host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
115 +
116 +               if (led_trigger_register(host->ports[i]->ledtrig)) {
117 +                       kfree(host->ports[i]->ledtrig);
118 +                       host->ports[i]->ledtrig = NULL;
119 +               }
120 +       }
121 +#endif
122         /* Create associated sysfs transport objects  */
123         for (i = 0; i < host->n_ports; i++) {
124                 rc = ata_tport_add(host->dev,host->ports[i]);
125 --- a/include/linux/libata.h
126 +++ b/include/linux/libata.h
127 @@ -39,6 +39,9 @@
128  #include <linux/cdrom.h>
129  #include <linux/sched.h>
130  #include <linux/async.h>
131 +#ifdef CONFIG_ATA_LEDS
132 +#include <linux/leds.h>
133 +#endif
134  
135  /*
136   * Define if arch has non-standard setup.  This is a _PCI_ standard
137 @@ -896,6 +899,12 @@ struct ata_port {
138  #ifdef CONFIG_ATA_ACPI
139         struct ata_acpi_gtm     __acpi_init_gtm; /* use ata_acpi_init_gtm() */
140  #endif
141 +
142 +#ifdef CONFIG_ATA_LEDS
143 +       struct led_trigger      *ledtrig;
144 +       char                    ledtrig_name[8];
145 +#endif
146 +
147         /* owned by EH */
148         u8                      sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
149  };