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