Blame view

arch/sh/drivers/heartbeat.c 4.17 KB
401e9093a   Paul Mundt   sh: Compile fix f...
1
2
3
  /*
   * Generic heartbeat driver for regular LED banks
   *
10ab92d8c   Paul Mundt   sh: heartbeat: Su...
4
   * Copyright (C) 2007 - 2010  Paul Mundt
401e9093a   Paul Mundt   sh: Compile fix f...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   *
   * Most SH reference boards include a number of individual LEDs that can
   * be independently controlled (either via a pre-defined hardware
   * function or via the LED class, if desired -- the hardware tends to
   * encapsulate some of the same "triggers" that the LED class supports,
   * so there's not too much value in it).
   *
   * Additionally, most of these boards also have a LED bank that we've
   * traditionally used for strobing the load average. This use case is
   * handled by this driver, rather than giving each LED bit position its
   * own struct device.
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
   * for more details.
   */
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/sched.h>
  #include <linux/timer.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
8786c952c   Paul Mundt   sh: heartbeat dri...
28
  #include <asm/heartbeat.h>
401e9093a   Paul Mundt   sh: Compile fix f...
29
30
  
  #define DRV_NAME "heartbeat"
10ab92d8c   Paul Mundt   sh: heartbeat: Su...
31
  #define DRV_VERSION "0.1.2"
401e9093a   Paul Mundt   sh: Compile fix f...
32

8786c952c   Paul Mundt   sh: heartbeat dri...
33
34
35
36
37
38
39
40
41
42
  static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
  
  static inline void heartbeat_toggle_bit(struct heartbeat_data *hd,
  					unsigned bit, unsigned int inverted)
  {
  	unsigned int new;
  
  	new = (1 << hd->bit_pos[bit]);
  	if (inverted)
  		new = ~new;
e174d1301   Kuninori Morimoto   sh: Prevent heart...
43
  	new &= hd->mask;
8786c952c   Paul Mundt   sh: heartbeat dri...
44
45
  	switch (hd->regsize) {
  	case 32:
e174d1301   Kuninori Morimoto   sh: Prevent heart...
46
  		new |= ioread32(hd->base) & ~hd->mask;
8786c952c   Paul Mundt   sh: heartbeat dri...
47
48
49
  		iowrite32(new, hd->base);
  		break;
  	case 16:
e174d1301   Kuninori Morimoto   sh: Prevent heart...
50
  		new |= ioread16(hd->base) & ~hd->mask;
8786c952c   Paul Mundt   sh: heartbeat dri...
51
52
53
  		iowrite16(new, hd->base);
  		break;
  	default:
e174d1301   Kuninori Morimoto   sh: Prevent heart...
54
  		new |= ioread8(hd->base) & ~hd->mask;
8786c952c   Paul Mundt   sh: heartbeat dri...
55
56
57
58
  		iowrite8(new, hd->base);
  		break;
  	}
  }
401e9093a   Paul Mundt   sh: Compile fix f...
59
60
61
62
63
  
  static void heartbeat_timer(unsigned long data)
  {
  	struct heartbeat_data *hd = (struct heartbeat_data *)data;
  	static unsigned bit = 0, up = 1;
8786c952c   Paul Mundt   sh: heartbeat dri...
64
  	heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED);
f6072896e   Takashi YOSHII   sh: heartbeat dou...
65
  	bit += up;
8786c952c   Paul Mundt   sh: heartbeat dri...
66
  	if ((bit == 0) || (bit == (hd->nr_bits)-1))
f6072896e   Takashi YOSHII   sh: heartbeat dou...
67
  		up = -up;
401e9093a   Paul Mundt   sh: Compile fix f...
68
69
70
71
72
73
74
75
76
  
  	mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
  			((avenrun[0] / 5) + (3 << FSHIFT)))));
  }
  
  static int heartbeat_drv_probe(struct platform_device *pdev)
  {
  	struct resource *res;
  	struct heartbeat_data *hd;
e174d1301   Kuninori Morimoto   sh: Prevent heart...
77
  	int i;
401e9093a   Paul Mundt   sh: Compile fix f...
78
79
80
81
82
83
84
85
86
87
88
89
90
  
  	if (unlikely(pdev->num_resources != 1)) {
  		dev_err(&pdev->dev, "invalid number of resources
  ");
  		return -EINVAL;
  	}
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (unlikely(res == NULL)) {
  		dev_err(&pdev->dev, "invalid resource
  ");
  		return -EINVAL;
  	}
401e9093a   Paul Mundt   sh: Compile fix f...
91
  	if (pdev->dev.platform_data) {
8786c952c   Paul Mundt   sh: heartbeat dri...
92
  		hd = pdev->dev.platform_data;
401e9093a   Paul Mundt   sh: Compile fix f...
93
  	} else {
8786c952c   Paul Mundt   sh: heartbeat dri...
94
95
96
97
  		hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
  		if (unlikely(!hd))
  			return -ENOMEM;
  	}
10ab92d8c   Paul Mundt   sh: heartbeat: Su...
98
  	hd->base = ioremap_nocache(res->start, resource_size(res));
1de83e94e   Roel Kluin   sh: heartbeat: io...
99
  	if (unlikely(!hd->base)) {
8786c952c   Paul Mundt   sh: heartbeat dri...
100
101
102
103
104
105
106
107
  		dev_err(&pdev->dev, "ioremap failed
  ");
  
  		if (!pdev->dev.platform_data)
  			kfree(hd);
  
  		return -ENXIO;
  	}
401e9093a   Paul Mundt   sh: Compile fix f...
108

8786c952c   Paul Mundt   sh: heartbeat dri...
109
110
111
  	if (!hd->nr_bits) {
  		hd->bit_pos = default_bit_pos;
  		hd->nr_bits = ARRAY_SIZE(default_bit_pos);
401e9093a   Paul Mundt   sh: Compile fix f...
112
  	}
e174d1301   Kuninori Morimoto   sh: Prevent heart...
113
114
115
  	hd->mask = 0;
  	for (i = 0; i < hd->nr_bits; i++)
  		hd->mask |= (1 << hd->bit_pos[i]);
10ab92d8c   Paul Mundt   sh: heartbeat: Su...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  	if (!hd->regsize) {
  		switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
  		case IORESOURCE_MEM_32BIT:
  			hd->regsize = 32;
  			break;
  		case IORESOURCE_MEM_16BIT:
  			hd->regsize = 16;
  			break;
  		case IORESOURCE_MEM_8BIT:
  		default:
  			hd->regsize = 8;
  			break;
  		}
  	}
401e9093a   Paul Mundt   sh: Compile fix f...
130
131
132
133
134
135
136
137
138
139
140
141
  
  	setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
  	platform_set_drvdata(pdev, hd);
  
  	return mod_timer(&hd->timer, jiffies + 1);
  }
  
  static int heartbeat_drv_remove(struct platform_device *pdev)
  {
  	struct heartbeat_data *hd = platform_get_drvdata(pdev);
  
  	del_timer_sync(&hd->timer);
8786c952c   Paul Mundt   sh: heartbeat dri...
142
  	iounmap(hd->base);
401e9093a   Paul Mundt   sh: Compile fix f...
143
144
  
  	platform_set_drvdata(pdev, NULL);
8786c952c   Paul Mundt   sh: heartbeat dri...
145
146
  	if (!pdev->dev.platform_data)
  		kfree(hd);
401e9093a   Paul Mundt   sh: Compile fix f...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  
  	return 0;
  }
  
  static struct platform_driver heartbeat_driver = {
  	.probe		= heartbeat_drv_probe,
  	.remove		= heartbeat_drv_remove,
  	.driver		= {
  		.name	= DRV_NAME,
  	},
  };
  
  static int __init heartbeat_init(void)
  {
  	printk(KERN_NOTICE DRV_NAME ": version %s loaded
  ", DRV_VERSION);
  	return platform_driver_register(&heartbeat_driver);
  }
  
  static void __exit heartbeat_exit(void)
  {
  	platform_driver_unregister(&heartbeat_driver);
  }
  module_init(heartbeat_init);
  module_exit(heartbeat_exit);
  
  MODULE_VERSION(DRV_VERSION);
  MODULE_AUTHOR("Paul Mundt");
839cd3105   Al Viro   MODULE_LICENSE ex...
175
  MODULE_LICENSE("GPL v2");