diff options
author | Michael Grzeschik <m.grzeschik@pengutronix.de> | 2014-09-17 18:12:50 -0400 |
---|---|---|
committer | Michael Grzeschik <m.grzeschik@pengutronix.de> | 2015-10-26 04:10:56 -0400 |
commit | 8890624a4e8c2c7046d63bfd15d7331af9f55f10 (patch) | |
tree | c99553d5963e353f9375206f1654fcc920d2da1b | |
parent | 5ef216c1f84825c6942fdd6c24d12a08ac2df135 (diff) |
arcnet: com20020-pci: add led trigger support
The EAE PLX-PCI card has special leds on the the main io pci resource
bar. This patch adds support to trigger the conflict and data leds with
the packages.
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
-rw-r--r-- | drivers/net/arcnet/arcdevice.h | 19 | ||||
-rw-r--r-- | drivers/net/arcnet/arcnet.c | 72 | ||||
-rw-r--r-- | drivers/net/arcnet/com20020-pci.c | 73 | ||||
-rw-r--r-- | drivers/net/arcnet/com20020.h | 10 | ||||
-rw-r--r-- | include/linux/leds.h | 7 |
5 files changed, 181 insertions, 0 deletions
diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h index d7fdea11e694..2edc0c0ab7c7 100644 --- a/drivers/net/arcnet/arcdevice.h +++ b/drivers/net/arcnet/arcdevice.h | |||
@@ -237,6 +237,8 @@ struct Outgoing { | |||
237 | numsegs; /* number of segments */ | 237 | numsegs; /* number of segments */ |
238 | }; | 238 | }; |
239 | 239 | ||
240 | #define ARCNET_LED_NAME_SZ (IFNAMSIZ + 6) | ||
241 | |||
240 | struct arcnet_local { | 242 | struct arcnet_local { |
241 | uint8_t config, /* current value of CONFIG register */ | 243 | uint8_t config, /* current value of CONFIG register */ |
242 | timeout, /* Extended timeout for COM20020 */ | 244 | timeout, /* Extended timeout for COM20020 */ |
@@ -260,6 +262,11 @@ struct arcnet_local { | |||
260 | /* On preemtive and SMB a lock is needed */ | 262 | /* On preemtive and SMB a lock is needed */ |
261 | spinlock_t lock; | 263 | spinlock_t lock; |
262 | 264 | ||
265 | struct led_trigger *tx_led_trig; | ||
266 | char tx_led_trig_name[ARCNET_LED_NAME_SZ]; | ||
267 | struct led_trigger *recon_led_trig; | ||
268 | char recon_led_trig_name[ARCNET_LED_NAME_SZ]; | ||
269 | |||
263 | /* | 270 | /* |
264 | * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of | 271 | * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of |
265 | * which can be used for either sending or receiving. The new dynamic | 272 | * which can be used for either sending or receiving. The new dynamic |
@@ -309,6 +316,8 @@ struct arcnet_local { | |||
309 | int (*reset)(struct net_device *dev, int really_reset); | 316 | int (*reset)(struct net_device *dev, int really_reset); |
310 | void (*open)(struct net_device *dev); | 317 | void (*open)(struct net_device *dev); |
311 | void (*close)(struct net_device *dev); | 318 | void (*close)(struct net_device *dev); |
319 | void (*datatrigger) (struct net_device * dev, int enable); | ||
320 | void (*recontrigger) (struct net_device * dev, int enable); | ||
312 | 321 | ||
313 | void (*copy_to_card)(struct net_device *dev, int bufnum, | 322 | void (*copy_to_card)(struct net_device *dev, int bufnum, |
314 | int offset, void *buf, int count); | 323 | int offset, void *buf, int count); |
@@ -319,6 +328,16 @@ struct arcnet_local { | |||
319 | void __iomem *mem_start; /* pointer to ioremap'ed MMIO */ | 328 | void __iomem *mem_start; /* pointer to ioremap'ed MMIO */ |
320 | }; | 329 | }; |
321 | 330 | ||
331 | enum arcnet_led_event { | ||
332 | ARCNET_LED_EVENT_RECON, | ||
333 | ARCNET_LED_EVENT_OPEN, | ||
334 | ARCNET_LED_EVENT_STOP, | ||
335 | ARCNET_LED_EVENT_TX, | ||
336 | }; | ||
337 | |||
338 | void arcnet_led_event(struct net_device *netdev, enum arcnet_led_event event); | ||
339 | void devm_arcnet_led_init(struct net_device *netdev, int index, int subid); | ||
340 | |||
322 | #if ARCNET_DEBUG_MAX & D_SKB | 341 | #if ARCNET_DEBUG_MAX & D_SKB |
323 | void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); | 342 | void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); |
324 | #else | 343 | #else |
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 542e2b46b9eb..4242522ae86b 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c | |||
@@ -52,6 +52,8 @@ | |||
52 | #include <linux/init.h> | 52 | #include <linux/init.h> |
53 | #include <linux/jiffies.h> | 53 | #include <linux/jiffies.h> |
54 | 54 | ||
55 | #include <linux/leds.h> | ||
56 | |||
55 | #include "arcdevice.h" | 57 | #include "arcdevice.h" |
56 | #include "com9026.h" | 58 | #include "com9026.h" |
57 | 59 | ||
@@ -189,6 +191,71 @@ static void arcnet_dump_packet(struct net_device *dev, int bufnum, | |||
189 | 191 | ||
190 | #endif | 192 | #endif |
191 | 193 | ||
194 | /* Trigger a LED event in response to a ARCNET device event */ | ||
195 | void arcnet_led_event(struct net_device *dev, enum arcnet_led_event event) | ||
196 | { | ||
197 | struct arcnet_local *lp = netdev_priv(dev); | ||
198 | unsigned long led_delay = 350; | ||
199 | unsigned long tx_delay = 50; | ||
200 | |||
201 | switch (event) { | ||
202 | case ARCNET_LED_EVENT_RECON: | ||
203 | led_trigger_blink_oneshot(lp->recon_led_trig, | ||
204 | &led_delay, &led_delay, 0); | ||
205 | break; | ||
206 | case ARCNET_LED_EVENT_OPEN: | ||
207 | led_trigger_event(lp->tx_led_trig, LED_OFF); | ||
208 | led_trigger_event(lp->recon_led_trig, LED_OFF); | ||
209 | break; | ||
210 | case ARCNET_LED_EVENT_STOP: | ||
211 | led_trigger_event(lp->tx_led_trig, LED_OFF); | ||
212 | led_trigger_event(lp->recon_led_trig, LED_OFF); | ||
213 | break; | ||
214 | case ARCNET_LED_EVENT_TX: | ||
215 | led_trigger_blink_oneshot(lp->tx_led_trig, | ||
216 | &tx_delay, &tx_delay, 0); | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(arcnet_led_event); | ||
221 | |||
222 | static void arcnet_led_release(struct device *gendev, void *res) | ||
223 | { | ||
224 | struct arcnet_local *lp = netdev_priv(to_net_dev(gendev)); | ||
225 | |||
226 | led_trigger_unregister_simple(lp->tx_led_trig); | ||
227 | led_trigger_unregister_simple(lp->recon_led_trig); | ||
228 | } | ||
229 | |||
230 | /* Register ARCNET LED triggers for a arcnet device | ||
231 | * | ||
232 | * This is normally called from a driver's probe function | ||
233 | */ | ||
234 | void devm_arcnet_led_init(struct net_device *netdev, int index, int subid) | ||
235 | { | ||
236 | struct arcnet_local *lp = netdev_priv(netdev); | ||
237 | void *res; | ||
238 | |||
239 | res = devres_alloc(arcnet_led_release, 0, GFP_KERNEL); | ||
240 | if (!res) { | ||
241 | netdev_err(netdev, "cannot register LED triggers\n"); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | snprintf(lp->tx_led_trig_name, sizeof(lp->tx_led_trig_name), | ||
246 | "arc%d-%d-tx", index, subid); | ||
247 | snprintf(lp->recon_led_trig_name, sizeof(lp->recon_led_trig_name), | ||
248 | "arc%d-%d-recon", index, subid); | ||
249 | |||
250 | led_trigger_register_simple(lp->tx_led_trig_name, | ||
251 | &lp->tx_led_trig); | ||
252 | led_trigger_register_simple(lp->recon_led_trig_name, | ||
253 | &lp->recon_led_trig); | ||
254 | |||
255 | devres_add(&netdev->dev, res); | ||
256 | } | ||
257 | EXPORT_SYMBOL_GPL(devm_arcnet_led_init); | ||
258 | |||
192 | /* Unregister a protocol driver from the arc_proto_map. Protocol drivers | 259 | /* Unregister a protocol driver from the arc_proto_map. Protocol drivers |
193 | * are responsible for registering themselves, but the unregister routine | 260 | * are responsible for registering themselves, but the unregister routine |
194 | * is pretty generic so we'll do it here. | 261 | * is pretty generic so we'll do it here. |
@@ -425,6 +492,7 @@ int arcnet_open(struct net_device *dev) | |||
425 | 492 | ||
426 | netif_start_queue(dev); | 493 | netif_start_queue(dev); |
427 | 494 | ||
495 | arcnet_led_event(dev, ARCNET_LED_EVENT_OPEN); | ||
428 | return 0; | 496 | return 0; |
429 | 497 | ||
430 | out_module_put: | 498 | out_module_put: |
@@ -438,6 +506,7 @@ int arcnet_close(struct net_device *dev) | |||
438 | { | 506 | { |
439 | struct arcnet_local *lp = netdev_priv(dev); | 507 | struct arcnet_local *lp = netdev_priv(dev); |
440 | 508 | ||
509 | arcnet_led_event(dev, ARCNET_LED_EVENT_STOP); | ||
441 | netif_stop_queue(dev); | 510 | netif_stop_queue(dev); |
442 | 511 | ||
443 | /* flush TX and disable RX */ | 512 | /* flush TX and disable RX */ |
@@ -585,6 +654,8 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, | |||
585 | arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n", | 654 | arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n", |
586 | __FILE__, __LINE__, __func__, lp->hw.status(dev)); | 655 | __FILE__, __LINE__, __func__, lp->hw.status(dev)); |
587 | 656 | ||
657 | arcnet_led_event(dev, ARCNET_LED_EVENT_TX); | ||
658 | |||
588 | spin_unlock_irqrestore(&lp->lock, flags); | 659 | spin_unlock_irqrestore(&lp->lock, flags); |
589 | return retval; /* no need to try again */ | 660 | return retval; /* no need to try again */ |
590 | } | 661 | } |
@@ -837,6 +908,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) | |||
837 | 908 | ||
838 | arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n", | 909 | arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n", |
839 | status); | 910 | status); |
911 | arcnet_led_event(dev, ARCNET_LED_EVENT_RECON); | ||
840 | /* MYRECON bit is at bit 7 of diagstatus */ | 912 | /* MYRECON bit is at bit 7 of diagstatus */ |
841 | if (diagstatus & 0x80) | 913 | if (diagstatus & 0x80) |
842 | arc_printk(D_RECON, dev, "Put out that recon myself\n"); | 914 | arc_printk(D_RECON, dev, "Put out that recon myself\n"); |
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 637a6110cec6..239de38fbd6a 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
42 | #include <linux/list.h> | 42 | #include <linux/list.h> |
43 | #include <linux/io.h> | 43 | #include <linux/io.h> |
44 | #include <linux/leds.h> | ||
44 | 45 | ||
45 | #include "arcdevice.h" | 46 | #include "arcdevice.h" |
46 | #include "com20020.h" | 47 | #include "com20020.h" |
@@ -62,6 +63,36 @@ module_param(clockp, int, 0); | |||
62 | module_param(clockm, int, 0); | 63 | module_param(clockm, int, 0); |
63 | MODULE_LICENSE("GPL"); | 64 | MODULE_LICENSE("GPL"); |
64 | 65 | ||
66 | static void led_tx_set(struct led_classdev *led_cdev, | ||
67 | enum led_brightness value) | ||
68 | { | ||
69 | struct com20020_dev *card; | ||
70 | struct com20020_priv *priv; | ||
71 | struct com20020_pci_card_info *ci; | ||
72 | |||
73 | card = container_of(led_cdev, struct com20020_dev, tx_led); | ||
74 | |||
75 | priv = card->pci_priv; | ||
76 | ci = priv->ci; | ||
77 | |||
78 | outb(!!value, priv->misc + ci->leds[card->index].green); | ||
79 | } | ||
80 | |||
81 | static void led_recon_set(struct led_classdev *led_cdev, | ||
82 | enum led_brightness value) | ||
83 | { | ||
84 | struct com20020_dev *card; | ||
85 | struct com20020_priv *priv; | ||
86 | struct com20020_pci_card_info *ci; | ||
87 | |||
88 | card = container_of(led_cdev, struct com20020_dev, recon_led); | ||
89 | |||
90 | priv = card->pci_priv; | ||
91 | ci = priv->ci; | ||
92 | |||
93 | outb(!!value, priv->misc + ci->leds[card->index].red); | ||
94 | } | ||
95 | |||
65 | static void com20020pci_remove(struct pci_dev *pdev); | 96 | static void com20020pci_remove(struct pci_dev *pdev); |
66 | 97 | ||
67 | static int com20020pci_probe(struct pci_dev *pdev, | 98 | static int com20020pci_probe(struct pci_dev *pdev, |
@@ -170,14 +201,41 @@ static int com20020pci_probe(struct pci_dev *pdev, | |||
170 | 201 | ||
171 | card->index = i; | 202 | card->index = i; |
172 | card->pci_priv = priv; | 203 | card->pci_priv = priv; |
204 | card->tx_led.brightness_set = led_tx_set; | ||
205 | card->tx_led.default_trigger = devm_kasprintf(&pdev->dev, | ||
206 | GFP_KERNEL, "arc%d-%d-tx", | ||
207 | dev->dev_id, i); | ||
208 | card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, | ||
209 | "pci:green:tx:%d-%d", | ||
210 | dev->dev_id, i); | ||
211 | |||
212 | card->tx_led.dev = &dev->dev; | ||
213 | card->recon_led.brightness_set = led_recon_set; | ||
214 | card->recon_led.default_trigger = devm_kasprintf(&pdev->dev, | ||
215 | GFP_KERNEL, "arc%d-%d-recon", | ||
216 | dev->dev_id, i); | ||
217 | card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, | ||
218 | "pci:red:recon:%d-%d", | ||
219 | dev->dev_id, i); | ||
220 | card->recon_led.dev = &dev->dev; | ||
173 | card->dev = dev; | 221 | card->dev = dev; |
174 | 222 | ||
223 | ret = devm_led_classdev_register(&pdev->dev, &card->tx_led); | ||
224 | if (ret) | ||
225 | goto out_port; | ||
226 | |||
227 | ret = devm_led_classdev_register(&pdev->dev, &card->recon_led); | ||
228 | if (ret) | ||
229 | goto out_port; | ||
230 | |||
175 | dev_set_drvdata(&dev->dev, card); | 231 | dev_set_drvdata(&dev->dev, card); |
176 | 232 | ||
177 | ret = com20020_found(dev, IRQF_SHARED); | 233 | ret = com20020_found(dev, IRQF_SHARED); |
178 | if (ret) | 234 | if (ret) |
179 | goto out_port; | 235 | goto out_port; |
180 | 236 | ||
237 | devm_arcnet_led_init(dev, dev->dev_id, i); | ||
238 | |||
181 | list_add(&card->list, &priv->list_dev); | 239 | list_add(&card->list, &priv->list_dev); |
182 | } | 240 | } |
183 | 241 | ||
@@ -261,6 +319,12 @@ static struct com20020_pci_card_info card_info_eae_arc1 = { | |||
261 | .offset = 0x10, | 319 | .offset = 0x10, |
262 | .size = 0x04, | 320 | .size = 0x04, |
263 | }, | 321 | }, |
322 | .leds = { | ||
323 | { | ||
324 | .green = 0x0, | ||
325 | .red = 0x1, | ||
326 | }, | ||
327 | }, | ||
264 | .rotary = 0x0, | 328 | .rotary = 0x0, |
265 | .flags = ARC_CAN_10MBIT, | 329 | .flags = ARC_CAN_10MBIT, |
266 | }; | 330 | }; |
@@ -284,6 +348,15 @@ static struct com20020_pci_card_info card_info_eae_ma1 = { | |||
284 | .offset = 0x10, | 348 | .offset = 0x10, |
285 | .size = 0x04, | 349 | .size = 0x04, |
286 | }, | 350 | }, |
351 | .leds = { | ||
352 | { | ||
353 | .green = 0x0, | ||
354 | .red = 0x1, | ||
355 | }, { | ||
356 | .green = 0x2, | ||
357 | .red = 0x3, | ||
358 | }, | ||
359 | }, | ||
287 | .rotary = 0x0, | 360 | .rotary = 0x0, |
288 | .flags = ARC_CAN_10MBIT, | 361 | .flags = ARC_CAN_10MBIT, |
289 | }; | 362 | }; |
diff --git a/drivers/net/arcnet/com20020.h b/drivers/net/arcnet/com20020.h index f2ed2eff3ae3..0bcc5d0a6903 100644 --- a/drivers/net/arcnet/com20020.h +++ b/drivers/net/arcnet/com20020.h | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | #ifndef __COM20020_H | 27 | #ifndef __COM20020_H |
28 | #define __COM20020_H | 28 | #define __COM20020_H |
29 | #include <linux/leds.h> | ||
29 | 30 | ||
30 | int com20020_check(struct net_device *dev); | 31 | int com20020_check(struct net_device *dev); |
31 | int com20020_found(struct net_device *dev, int shared); | 32 | int com20020_found(struct net_device *dev, int shared); |
@@ -36,6 +37,11 @@ extern const struct net_device_ops com20020_netdev_ops; | |||
36 | 37 | ||
37 | #define PLX_PCI_MAX_CARDS 2 | 38 | #define PLX_PCI_MAX_CARDS 2 |
38 | 39 | ||
40 | struct ledoffsets { | ||
41 | int green; | ||
42 | int red; | ||
43 | }; | ||
44 | |||
39 | struct com20020_pci_channel_map { | 45 | struct com20020_pci_channel_map { |
40 | u32 bar; | 46 | u32 bar; |
41 | u32 offset; | 47 | u32 offset; |
@@ -49,6 +55,7 @@ struct com20020_pci_card_info { | |||
49 | struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; | 55 | struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; |
50 | struct com20020_pci_channel_map misc_map; | 56 | struct com20020_pci_channel_map misc_map; |
51 | 57 | ||
58 | struct ledoffsets leds[PLX_PCI_MAX_CARDS]; | ||
52 | int rotary; | 59 | int rotary; |
53 | 60 | ||
54 | unsigned int flags; | 61 | unsigned int flags; |
@@ -64,6 +71,9 @@ struct com20020_dev { | |||
64 | struct list_head list; | 71 | struct list_head list; |
65 | struct net_device *dev; | 72 | struct net_device *dev; |
66 | 73 | ||
74 | struct led_classdev tx_led; | ||
75 | struct led_classdev recon_led; | ||
76 | |||
67 | struct com20020_priv *pci_priv; | 77 | struct com20020_priv *pci_priv; |
68 | int index; | 78 | int index; |
69 | }; | 79 | }; |
diff --git a/include/linux/leds.h b/include/linux/leds.h index b122eeafb5dc..fa359c79c825 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
@@ -283,6 +283,13 @@ static inline void led_trigger_register_simple(const char *name, | |||
283 | static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} | 283 | static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} |
284 | static inline void led_trigger_event(struct led_trigger *trigger, | 284 | static inline void led_trigger_event(struct led_trigger *trigger, |
285 | enum led_brightness event) {} | 285 | enum led_brightness event) {} |
286 | static inline void led_trigger_blink(struct led_trigger *trigger, | ||
287 | unsigned long *delay_on, | ||
288 | unsigned long *delay_off) {} | ||
289 | static inline void led_trigger_blink_oneshot(struct led_trigger *trigger, | ||
290 | unsigned long *delay_on, | ||
291 | unsigned long *delay_off, | ||
292 | int invert) {} | ||
286 | static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} | 293 | static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} |
287 | static inline void led_trigger_set(struct led_classdev *led_cdev, | 294 | static inline void led_trigger_set(struct led_classdev *led_cdev, |
288 | struct led_trigger *trigger) {} | 295 | struct led_trigger *trigger) {} |