且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

hacking a friend's Linux buzzer driver in OK335xS

更新时间:2022-08-12 20:32:47

  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");