aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Grzeschik <m.grzeschik@pengutronix.de>2014-09-17 18:12:50 -0400
committerMichael Grzeschik <m.grzeschik@pengutronix.de>2015-10-26 04:10:56 -0400
commit8890624a4e8c2c7046d63bfd15d7331af9f55f10 (patch)
treec99553d5963e353f9375206f1654fcc920d2da1b
parent5ef216c1f84825c6942fdd6c24d12a08ac2df135 (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.h19
-rw-r--r--drivers/net/arcnet/arcnet.c72
-rw-r--r--drivers/net/arcnet/com20020-pci.c73
-rw-r--r--drivers/net/arcnet/com20020.h10
-rw-r--r--include/linux/leds.h7
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
240struct arcnet_local { 242struct 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
331enum 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
338void arcnet_led_event(struct net_device *netdev, enum arcnet_led_event event);
339void 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
323void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); 342void 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 */
195void 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}
220EXPORT_SYMBOL_GPL(arcnet_led_event);
221
222static 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 */
234void 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}
257EXPORT_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);
62module_param(clockm, int, 0); 63module_param(clockm, int, 0);
63MODULE_LICENSE("GPL"); 64MODULE_LICENSE("GPL");
64 65
66static 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
81static 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
65static void com20020pci_remove(struct pci_dev *pdev); 96static void com20020pci_remove(struct pci_dev *pdev);
66 97
67static int com20020pci_probe(struct pci_dev *pdev, 98static 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
30int com20020_check(struct net_device *dev); 31int com20020_check(struct net_device *dev);
31int com20020_found(struct net_device *dev, int shared); 32int 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
40struct ledoffsets {
41 int green;
42 int red;
43};
44
39struct com20020_pci_channel_map { 45struct 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,
283static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} 283static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {}
284static inline void led_trigger_event(struct led_trigger *trigger, 284static inline void led_trigger_event(struct led_trigger *trigger,
285 enum led_brightness event) {} 285 enum led_brightness event) {}
286static inline void led_trigger_blink(struct led_trigger *trigger,
287 unsigned long *delay_on,
288 unsigned long *delay_off) {}
289static inline void led_trigger_blink_oneshot(struct led_trigger *trigger,
290 unsigned long *delay_on,
291 unsigned long *delay_off,
292 int invert) {}
286static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} 293static inline void led_trigger_set_default(struct led_classdev *led_cdev) {}
287static inline void led_trigger_set(struct led_classdev *led_cdev, 294static inline void led_trigger_set(struct led_classdev *led_cdev,
288 struct led_trigger *trigger) {} 295 struct led_trigger *trigger) {}