1 /****************************************************************************
2 * hacking a friend's Linux buzzer driver in OK335xS
3 * 说明:
4 * 解读朋友的Linux buzzer驱动,作为后续相关编码的参考。
5 *
6 * 2015-8-25 晴 深圳 南山平山村 曾剑锋
7 ***************************************************************************/
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/leds.h>
11 #include <linux/io.h>
12 #include <linux/semaphore.h>
13 #include <linux/kernel.h>
14 #include <linux/cdev.h>
15 #include <linux/types.h>
16 #include <linux/fs.h>
17 #include <mach/gpio.h>
18 #include <plat/mux.h>
19 #include <linux/gpio.h>
20
21 #define IO_VAULE_H 5
22 #define IO_VAULE_L 6
23
24 /**
25 * 1. 参考文档:AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual (Rev. H).pdf
26 * 2. ARM Cortex-A8 Memory Map:
27 * Table 2-1. L3 Memory Map (page 155)
28 * +------------+---------------------+-------------------+------------------+
29 * | Block Name | Start_address (hex) | End_address (hex) | Size Description |
30 * +------------+---------------------+-------------------=------------------+
31 * | L4_WKUP | 0x44C0_0000 | 0x44FF_FFFF | 4MB L4_WKUP |
32 * +------------+---------------------+-------------------+------------------+
33 * Table 2-2. L4_WKUP Peripheral Memory Map (page 158)
34 * +----------------+---------------------+-------------------+-------+--------------------------+
35 * | Region Name | Start Address (hex) | End Address (hex) | Size | Description |
36 * +----------------+---------------------+-------------------+-------+--------------------------+
37 * | Control Module | 0x44E1_0000 | 0x44E1_1FFF | 128KB | Control Module Registers |
38 * +----------------+---------------------+-------------------+-------+--------------------------+
39 */
40 #define Control_Module_address 0x44E10000
41
42 /**
43 * 1. 参考文档:AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual (Rev. H).pdf
44 * 2. CONTROL_MODULE Registers:
45 * Table 9-10. CONTROL_MODULE REGISTERS
46 * +--------+---------------+----------------------+----------------+
47 * | Offset | Acronym | Register Description | Section |
48 * +--------+---------------+----------------------+----------------+
49 * | 960h | conf_spi0_cs1 | | Section 9.3.51 |
50 * +--------+---------------+----------------------+----------------+
51 */
52 #define CONFIG_SPI0_CS1_offset 0x960
53
54 /**
55 * can't find any reference for this define, but it can use
56 */
57 #define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio) )
58
59 /**
60 * just like container_of in kernel
61 */
62 #define GET_STRUCT_ADDR (ptr,type,member)\
63 ((unsigned long )ptr - (unsigned long)((type*)0->member))
64
65 /**
66 * 1. 参考文档:Sitara AM335x ARM Cortex-A8 Microprocessors (MPUs) (Rev. F).pdf
67 * Table 2-7. Ball Characteristics (ZCE and ZCZ Packages) (continued) (page 43)
68 * +-----------+-----------+-------------+--------------------+---------+---------+
69 * | ZCE BALL | ZCZ BALL | PIN NAME[2] | SIGNAL NAME[3] | MODE[4] | TYPE[5] |
70 * | NUMBER[1] | NUMBER[1] | | | | |
71 * +-----------+-----------+-------------+--------------------+---------+---------+
72 * | B16 | C15 | SPI0_CS1 | spi0_cs1 | 0 | I/O |
73 * | | | |--------------------|---------+---------+
74 * | | | | uart3_rxd | 1 | I |
75 * | | | |--------------------|---------+---------+
76 * | | | | eCAP1_in_PWM1_out | 2 | I/O |
77 * | | | |--------------------|---------+---------+
78 * | | | | mmc0_pow | 3 | O |
79 * | | | |--------------------|---------+---------+
80 * | | | | xdma_event_intr2 | 4 | I |
81 * | | | |--------------------|---------+---------+
82 * | | | | mmc0_sdcd | 5 | I |
83 * | | | |--------------------|---------+---------+
84 * | | | | EMU4 | 6 | I/O |
85 * | | | |--------------------|---------+---------+
86 * | | | | gpio0_6 | 7 | I/O |
87 * +-----------+-----------+-------------+--------------------+---------+---------+
88 */
89 #define BUZZER_PIN GPIO_TO_PIN(0, 6)
90
91 struct cdev * buzz;
92
93 static int buzz_init(void)
94 {
95 int result;
96
97 /**
98 * void *ioremap(unsigned long phys_addr, unsigned long size)
99 * 入口:phys_addr:要映射的起始的IO地址;
100 * size:要映射的空间的大小;
101 */
102 void __iomem * base = ioremap(Control_Module_address, 0x1FFF);
103 /**
104 * 1 参考文章:AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual (Rev. H).pdf
105 * Table 9-61. conf_<module>_<pin> Register Field Descriptions(page 815)
106 * +-------+-------------------------+--------------+-------------------------------------------+
107 * | Bit | Field | Type | Reset | Description |
108 * +-------+-------------------------+--------------+-------------------------------------------+
109 * | 31-20 | Reserved | R | 0h | |
110 * +-------+-------------------------+--------------+-------------------------------------------+
111 * | 19-7 | Reserved | R | 0h | |
112 * +-------+-------------------------+--------------+-------------------------------------------+
113 * | 6 | conf_<module>_<pin>_sle | R/W | X | Select between faster or slower slew rate |
114 * | | wctrl | | | 0: Fast |
115 * | | | | | 1: Slow |
116 * | | | | | Reset value is pad-dependent. |
117 * +-------+-------------------------+--------------+----------------------------------------- +
118 * | 5 | conf_<module>_<pin>_rx | R/W | 1h | Input enable value for the PAD |
119 * | | active | | | 0: Receiver disabled |
120 * | | | | | 1: Receiver enabled |
121 * +-------+-------------------------+--------------+----------------------------------------- +
122 * | 4 | conf_<module>_<pin>_pu | R/W | X | Pad pullup/pulldown type selection |
123 * | | typesel | | | 0: Pulldown selected |
124 * | | | | | 1: Pullup selected |
125 * | | | | | Reset value is pad-dependent. |
126 * +-------+-------------------------+--------------+-------------------------------------------+
127 * | 3 | conf_<module>_<pin>_pu | R/W | X | Pad pullup/pulldown enable |
128 * | | den | | | 0: Pullup/pulldown enabled |
129 * | | | | | 1: Pullup/pulldown disabled |
130 * | | | | | Reset value is pad-dependent. |
131 * +-------+-------------------------+--------------+-------------------------------------------+
132 * | 2-0 | conf_<module>_<pin>_m | R/W | X | Pad functional signal mux select. |
133 * | | mode | | | Reset value is pad-dependent. |
134 * +-------+-------------------------+--------------+-------------------------------------------+
135 * 2. 0x37 = B0011 0111
136 * 1. bit 6 --> 0 --> Fast;
137 * 2. bit 5 --> 1 --> Receiver enabled;
138 * 3. bit 4 --> 1 --> Pullup selected;
139 * 4. bit 3 --> 0 --> Pullup/pulldown enabled;
140 * 5. bit 2-0 --> 7 --> gpio0_6; 参考前面说明 #define BUZZER_PIN GPIO_TO_PIN(0,6)
141 */
142 __raw_writel(0x37, (base + CONFIG_SPI0_CS1_offset ));
143
144 /* Allocating GPIOs and setting direction */
145 result = gpio_request(BUZZER_PIN, "buzzer"); //usr1
146 if (result != 0)
147 printk("gpio_request(0_6) failed!\n"); return result;
148
149 result = gpio_direction_output(BUZZER_PIN, 1);
150 if (result != 0)
151 printk("gpio_direction(0_6) failed!\n"); return result;
152
153 gpio_set_value(BUZZER_PIN, 0);
154
155 return result;
156 }
157
158 static int buzz_open(struct inode *inode, struct file *file)
159 {
160 return 0;
161 }
162
163 static ssize_t buzz_read (struct file *file, char __user *buf, size_t size, loff_t * off)
164 {
165 return 0;
166 }
167
168 static int buzz_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
169 {
170 if(cmd == IO_VAULE_H ) {
171 printk(" buzz iotcl IO_VALUE_H.\n"); // for debug
172 gpio_set_value(BUZZER_PIN,1);
173 }
174 if(cmd == IO_VAULE_L ) {
175 printk(" buzz iotcl IO_VALUE_L.\n");
176 gpio_set_value(BUZZER_PIN,0);
177 }
178
179 return 0;
180 }
181
182 static ssize_t buzz_write (struct file *file, char __user *buf, size_t size, loff_t * off)
183 {
184 return 0;
185 }
186
187 static int buzz_release (struct inode *inode, struct file *file)
188 {
189 return 0;
190 }
191
192 struct file_operations buzz_fops = {
193 .owner = THIS_MODULE,
194 .open = buzz_open,
195 .read = buzz_read,
196 .write = buzz_write,
197 .release = buzz_release,
198 .unlocked_ioctl= buzz_ioctl
199 };
200
201 static int __init buzzm_init()
202 {
203 /**
204 * 表示静态的申请和注册设备号:
205 * register_chrdev_region(dev_t first,unsigned int count,char *name)
206 * first :要分配的设备编号范围的初始值(次设备号常设为0);
207 * count:连续编号范围.
208 * name:编号相关联的设备名称. (/proc/devices);
209 */
210 if(register_chrdev_region(MKDEV(301,0),1,"aple_buzz") < 0)
211 return -ENOMEM ;
212
213 /**
214 * 前面只是注册了设备号,后面要向内核添加设备了;
215 */
216 buzz = cdev_alloc();
217 if(buzz == NULL)
218 return -ENOMEM;
219
220 cdev_init(buzz , &buzz_fops);
221 cdev_add(buzz ,MKDEV(301,0),1);
222 buzz_init();
223 return 0;
224 }
225
226 static void __exit buzzm_exit()
227 {
228 cdev_del(buzz);
229 unregister_chrdev_region(MKDEV(301,0),1);
230 }
231
232
233 module_init(buzzm_init);
234 module_exit(buzzm_exit);
235 MODULE_AUTHOR("Danny Zhao");
236 MODULE_LICENSE("GPL");