├── ReadMe.md ├── demo └── ch36x_demo.c ├── driver ├── Makefile └── ch36x.c └── lib ├── ch36x_lib.c └── ch36x_lib.h /ReadMe.md: -------------------------------------------------------------------------------- 1 | # ch36x linux driver 2 | 3 | ## Description 4 | 5 | ​This directory contains 3 parts, pci/pcie driver, application library and example. This driver and application support pci bus interface chip ch365 and pcie bus interface chips ch367 and ch368. 6 | 7 | 1. Open "Terminal" 8 | 2. Switch to "driver" directory 9 | 3. Compile the driver using "make", you will see the module "ch36x.ko" if successful 10 | 4. Type "sudo make load" or "sudo insmod ch36x.ko" to load the driver dynamically 11 | 5. Type "sudo make unload" or "sudo rmmod ch36x.ko" to unload the driver 12 | 6. Type "sudo make install" to make the driver work permanently 13 | 7. Type "sudo make uninstall" to remove the driver 14 | 15 | ​Before the driver works, you should make sure that the ch36x device has been plugged in and is working properly, you can use shell command "lspci" or "dmesg" to confirm that, ID of ch365 is [4348]:[5049], VID of ch367/ch368 is [1C00]. 16 | 17 | ​If ch36x device works well, the driver will created devices named "ch36xpcix" in /dev directory. 18 | 19 | ## Note 20 | 21 | ​Any question, you can send feedback to mail: tech@wch.cn 22 | -------------------------------------------------------------------------------- /demo/ch36x_demo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ch365/ch367/ch368 PCI/PCIE application demo 3 | * 4 | * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd. 5 | * Web: http://wch.cn 6 | * Author: WCH 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * Cross-compile with cross-gcc -I /path/to/cross-kernel/include 14 | * 15 | * Update Log: 16 | * V1.0 - initial version 17 | * V1.1 - call new APIs with ch36x_lib 18 | * V1.2 - call SPI and I2C APIs with ch36x_lib 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "ch36x_lib.h" 28 | 29 | static const char *device = "/dev/ch36xpci0"; 30 | 31 | static void ch36x_demo_io_operate(int fd) 32 | { 33 | int ret; 34 | char c; 35 | uint32_t ibyte; 36 | uint32_t offset; 37 | uint8_t obyte; 38 | 39 | printf("\n---------- IO read write test ----------\n"); 40 | while (1) { 41 | printf("press w to write one byte, r to read one byte, q for quit.\n"); 42 | scanf("%c", &c); 43 | getchar(); 44 | if (c == 'q') 45 | break; 46 | switch (c) { 47 | case 'w': 48 | printf("input offset of io:\n"); 49 | scanf("%x", &offset); 50 | getchar(); 51 | printf("input write value:\n"); 52 | scanf("%x", &ibyte); 53 | getchar(); 54 | ret = ch36x_write_io_byte(fd, (uint8_t)offset, (uint8_t)ibyte); 55 | if (ret != 0) 56 | printf("io write fail.\n"); 57 | break; 58 | case 'r': 59 | printf("input offset of io:\n"); 60 | scanf("%x", &offset); 61 | getchar(); 62 | ret = ch36x_read_io_byte(fd, (uint8_t)offset, &obyte); 63 | if (ret != 0) 64 | printf("io read fail.\n"); 65 | printf("read byte: 0x%2x\n", obyte); 66 | break; 67 | default: 68 | break; 69 | } 70 | } 71 | } 72 | 73 | static void ch36x_demo_mem_operate(int fd) 74 | { 75 | int ret; 76 | char c; 77 | uint32_t ibyte; 78 | uint32_t offset; 79 | uint8_t obyte; 80 | 81 | printf("\n---------- Memory read write test ----------\n"); 82 | while (1) { 83 | printf("press w to write one byte, r to read one byte, q for quit.\n"); 84 | scanf("%c", &c); 85 | getchar(); 86 | if (c == 'q') 87 | break; 88 | switch (c) { 89 | case 'w': 90 | printf("input offset of mem:\n"); 91 | scanf("%x", &offset); 92 | getchar(); 93 | printf("input write value:\n"); 94 | scanf("%x", &ibyte); 95 | getchar(); 96 | ret = ch36x_write_mem_byte(fd, (uint16_t)offset, (uint8_t)ibyte); 97 | if (ret != 0) 98 | printf("memory write fail.\n"); 99 | break; 100 | case 'r': 101 | printf("input offset of mem:\n"); 102 | scanf("%x", &offset); 103 | getchar(); 104 | ret = ch36x_read_mem_byte(fd, (uint16_t)offset, &obyte); 105 | if (ret != 0) 106 | printf("memory read fail.\n"); 107 | printf("read byte: 0x%2x\n", obyte); 108 | break; 109 | default: 110 | break; 111 | } 112 | } 113 | } 114 | 115 | static void ch36x_demo_config_operate(int fd) 116 | { 117 | int ret; 118 | char c; 119 | uint32_t ibyte; 120 | uint32_t offset; 121 | uint8_t obyte; 122 | 123 | printf("\n---------- Config space read write test ----------\n"); 124 | while (1) { 125 | printf("press w to write one byte, r to read one byte, q for quit.\n"); 126 | scanf("%c", &c); 127 | getchar(); 128 | if (c == 'q') 129 | break; 130 | switch (c) { 131 | case 'w': 132 | printf("input offset of config space:\n"); 133 | scanf("%x", &offset); 134 | getchar(); 135 | printf("input write value:\n"); 136 | scanf("%x", &ibyte); 137 | getchar(); 138 | ret = ch36x_write_config_byte(fd, (uint8_t)offset, (uint8_t)ibyte); 139 | if (ret != 0) 140 | printf("config space write fail.\n"); 141 | break; 142 | case 'r': 143 | printf("input offset of config space:\n"); 144 | scanf("%x", &offset); 145 | getchar(); 146 | ret = ch36x_read_config_byte(fd, (uint8_t)offset, &obyte); 147 | if (ret != 0) 148 | printf("config space read fail.\n"); 149 | printf("read byte: 0x%2x\n", obyte); 150 | break; 151 | default: 152 | break; 153 | } 154 | } 155 | } 156 | 157 | static void ch36x_dmeo_isr_handler(int signo) 158 | { 159 | static int int_times = 0; 160 | 161 | printf("ch36x interrupt times: %d\n", int_times++); 162 | } 163 | 164 | static void ch36x_demo_isr_enable(int fd) 165 | { 166 | int ret; 167 | enum INTMODE mode = INT_FALLING; 168 | 169 | ret = ch36x_enable_isr(fd, mode); 170 | if (ret != 0) { 171 | printf("ch36x_enable_isr failed.\n"); 172 | return; 173 | } 174 | ch36x_set_int_routine(fd, ch36x_dmeo_isr_handler); 175 | } 176 | 177 | static void ch36x_demo_isr_disable(int fd) 178 | { 179 | int ret; 180 | 181 | ret = ch36x_disable_isr(fd); 182 | if (ret != 0) { 183 | printf("ch36x_disable_isr failed.\n"); 184 | return; 185 | } 186 | ch36x_set_int_routine(fd, NULL); 187 | } 188 | 189 | static void ch36x_demo_spi_operate(int fd) 190 | { 191 | /* bit0 of mode on SPI Freq, 0->31.3MHz, 1->15.6MHz */ 192 | /* bit1 of mode on SPI I/O Pinout, 0->SPI3(SCS/SCL/SDX), 1->SPI4(SCS/SCL/SDX/SDI) */ 193 | uint8_t mode = 0x01; 194 | int ret; 195 | uint32_t ilen, olen; 196 | uint8_t ibuffer[1024]; 197 | uint8_t obuffer[1024]; 198 | int i; 199 | 200 | printf("\n---------- SPI read write test ----------\n"); 201 | ret = ch36x_set_stream(fd, mode); 202 | if (ret) { 203 | printf("set stream error.\n"); 204 | return; 205 | } 206 | printf("input write length:\n"); 207 | scanf("%d", &ilen); 208 | getchar(); 209 | printf("input read length:\n"); 210 | scanf("%d", &olen); 211 | getchar(); 212 | memset(ibuffer, 0x55, sizeof(ibuffer)); 213 | ret = ch36x_stream_spi(fd, ibuffer, ilen, obuffer, olen); 214 | if (ret != 0) { 215 | printf("spi transfer fail.\n"); 216 | return; 217 | } 218 | printf("\n---------- read buffer ----------\n"); 219 | for (i = 0; i < olen; i++) { 220 | printf("\tobuffer[%d]: 0x%2x\n", i, obuffer[i]); 221 | } 222 | printf("\n"); 223 | } 224 | 225 | static void ch36x_demo_flash_operate(int fd) 226 | { 227 | /* bit0 of mode on SPI Freq, 0->31.3MHz, 1->15.6MHz */ 228 | /* bit1 of mode on SPI I/O Pinout, 0->SPI3(SCS/SCL/SDX), 1->SPI4(SCS/SCL/SDX/SDI) */ 229 | uint8_t mode = 0x01; 230 | int ret; 231 | uint32_t olen; 232 | uint32_t addr; 233 | uint8_t ibuffer[1024]; 234 | uint8_t obuffer[1024]; 235 | int i; 236 | 237 | printf("\n---------- flash read write test ----------\n"); 238 | ret = ch36x_set_stream(fd, mode); 239 | if (ret) { 240 | printf("set stream error.\n"); 241 | return; 242 | } 243 | printf("input flash addr:\n"); 244 | scanf("%d", &addr); 245 | getchar(); 246 | printf("please input string to write:\n"); 247 | scanf("%s", ibuffer); 248 | getchar(); 249 | ret = ch36x_flash_erase(fd, addr, strlen(ibuffer)); 250 | if (ret != 0) { 251 | printf("spi flash erase fail.\n"); 252 | return; 253 | } else { 254 | printf("spi flash addr [0x%x - 0x%x] erased successfully.\n", addr, addr + (uint32_t)strlen(ibuffer)); 255 | } 256 | ret = ch36x_flash_write(fd, addr, ibuffer, strlen(ibuffer)); 257 | if (ret != 0) { 258 | printf("spi flash write fail.\n"); 259 | return; 260 | } else { 261 | printf("spi flash addr [0x%x - 0x%x] wrote successfully.\n", addr, addr + (uint32_t)strlen(ibuffer)); 262 | } 263 | printf("input read length:\n"); 264 | scanf("%d", &olen); 265 | getchar(); 266 | printf("\n---------- read spi flash from addr %d ----------\n", addr); 267 | ret = ch36x_flash_read(fd, addr, obuffer, olen); 268 | if (ret != 0) { 269 | printf("spi flash read fail.\n"); 270 | return; 271 | } 272 | for (i = 0; i < olen; i++) { 273 | printf("\tobuffer[%d]: 0x%2x\n", i, obuffer[i]); 274 | } 275 | printf("\n"); 276 | } 277 | 278 | static void ch36x_demo_eeprom_operate(int fd) 279 | { 280 | int ret; 281 | uint32_t olen; 282 | uint32_t addr; 283 | uint32_t reg; 284 | uint8_t ibuffer[1024]; 285 | uint8_t obuffer[1024]; 286 | int i; 287 | 288 | printf("\n---------- eeprom read write test ----------\n"); 289 | printf("input device addr:\n"); 290 | scanf("%x", &addr); 291 | getchar(); 292 | printf("input data unit addr:\n"); 293 | scanf("%x", ®); 294 | getchar(); 295 | printf("please input string to write:\n"); 296 | scanf("%s", ibuffer); 297 | getchar(); 298 | ret = ch36x_i2c_write(fd, (uint8_t)addr, (uint8_t)reg, ibuffer, (uint32_t)strlen(ibuffer)); 299 | if (ret != 0) { 300 | printf("eeprom write fail.\n"); 301 | return; 302 | } else { 303 | printf("eeprom data addr [0x%x - 0x%x] wrote successfully.\n", reg, reg + (uint32_t)strlen(ibuffer)); 304 | } 305 | printf("input read length:\n"); 306 | scanf("%d", &olen); 307 | getchar(); 308 | printf("\n---------- read eeprom from addr %d ----------\n", reg); 309 | ret = ch36x_i2c_read(fd, (uint8_t)addr, (uint8_t)reg, obuffer, olen); 310 | if (ret != 0) { 311 | printf("eeprom read fail.\n"); 312 | return; 313 | } 314 | for (i = 0; i < olen; i++) { 315 | printf("\tobuffer[%d]: 0x%2x\n", i, obuffer[i]); 316 | } 317 | printf("\n"); 318 | } 319 | 320 | int main(int argc, char *argv[]) 321 | { 322 | int fd; 323 | int ret; 324 | char c; 325 | enum CHIP_TYPE chiptype; 326 | unsigned long iobase; 327 | unsigned long membase; 328 | int irq; 329 | 330 | fd = ch36x_open(device); 331 | if (fd < 0) { 332 | printf("ch36x_open error.\n"); 333 | goto exit; 334 | } 335 | 336 | ret = ch36x_get_chiptype(fd, &chiptype); 337 | if (ret != 0) { 338 | printf("ch36x_get_chiptype error.\n"); 339 | goto exit; 340 | } 341 | switch (chiptype) { 342 | case CHIP_CH365: 343 | printf("current chip model: CH365.\n"); 344 | break; 345 | case CHIP_CH367: 346 | printf("current chip model: CH367.\n"); 347 | break; 348 | case CHIP_CH368: 349 | printf("current chip model: CH368.\n"); 350 | break; 351 | } 352 | 353 | ret = ch36x_get_irq(fd, &irq); 354 | if (ret != 0) { 355 | printf("ch36x_get_irq error.\n"); 356 | goto exit; 357 | } 358 | printf("irq number:%d\n", irq); 359 | 360 | ret = ch36x_get_ioaddr(fd, &iobase); 361 | if (ret != 0) { 362 | printf("ch36x_get_ioaddr error.\n"); 363 | goto exit; 364 | } 365 | printf("iobase:%lx\n", iobase); 366 | 367 | if (chiptype == CHIP_CH368) { 368 | ret = ch36x_get_memaddr(fd, &membase); 369 | if (ret != 0) { 370 | printf("ch36x_get_memaddr error.\n"); 371 | goto exit; 372 | } 373 | printf("membase:%lx\n", membase); 374 | } 375 | 376 | while (1) { 377 | printf("press c to operate config space, m to operate memory space, " 378 | "i to operate io space, e to enable interrupt, " 379 | "d to disable interrpt, s to operate spi, " 380 | "f to operate spi flash, p to operate eeprom, " 381 | "q for quit.\n"); 382 | scanf("%c", &c); 383 | getchar(); 384 | if (c == 'q') 385 | break; 386 | switch (c) { 387 | case 'i': 388 | ch36x_demo_io_operate(fd); 389 | break; 390 | case 'm': 391 | if (chiptype == CHIP_CH368) 392 | ch36x_demo_mem_operate(fd); 393 | else 394 | printf("chip not support.\n"); 395 | break; 396 | case 'c': 397 | ch36x_demo_config_operate(fd); 398 | break; 399 | case 'e': 400 | ch36x_demo_isr_enable(fd); 401 | break; 402 | case 'd': 403 | ch36x_demo_isr_disable(fd); 404 | break; 405 | case 's': 406 | ch36x_demo_spi_operate(fd); 407 | break; 408 | case 'f': 409 | ch36x_demo_flash_operate(fd); 410 | break; 411 | case 'p': 412 | ch36x_demo_eeprom_operate(fd); 413 | default: 414 | break; 415 | } 416 | } 417 | 418 | ret = ch36x_close(fd); 419 | if (ret != 0) { 420 | printf("ch36x_close error.\n"); 421 | goto exit; 422 | } 423 | 424 | exit: 425 | return ret; 426 | } 427 | -------------------------------------------------------------------------------- /driver/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(KERNELRELEASE), ) 2 | KERNELDIR := /lib/modules/$(shell uname -r)/build 3 | PWD :=$(shell pwd) 4 | default: 5 | $(MAKE) -C $(KERNELDIR) M=$(PWD) 6 | clean: 7 | rm -rf *.mk .tmp_versions Module.symvers *.mod.c *.o *.ko .*.cmd Module.markers modules.order *.mod *.a 8 | load: 9 | insmod ch36x.ko 10 | unload: 11 | rmmod ch36x 12 | install: default 13 | insmod ch36x.ko 14 | mkdir -p /lib/modules/$(shell uname -r)/kernel/drivers/misc/ 15 | cp -f ./ch36x.ko /lib/modules/$(shell uname -r)/kernel/drivers/misc/ 16 | depmod -a 17 | uninstall: 18 | rmmod ch36x.ko 19 | rm -rf /lib/modules/$(shell uname -r)/kernel/drivers/misc/ch36x.ko 20 | depmod -a 21 | else 22 | obj-m := ch36x.o 23 | endif 24 | -------------------------------------------------------------------------------- /driver/ch36x.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ch365/ch367/ch368 PCI/PCIE device driver 3 | * 4 | * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd. 5 | * Web: http://wch.cn 6 | * Author: WCH 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * Update Log: 14 | * V1.0 - initial version 15 | * V1.1 - modify io read/write methods with standard api not pointer access. 16 | * V1.2 - modify io/mem mapping, fix usage of interruption. 17 | * - add ioctl methods for spi transfer 18 | * - fix bugs of spi transfer 19 | * V1.3 - fix bugs of memory block read/write 20 | */ 21 | 22 | #define DEBUG 23 | #define VERBOSE_DEBUG 24 | 25 | #undef DEBUG 26 | #undef VERBOSE_DEBUG 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #define DRIVER_AUTHOR "WCH" 51 | #define DRIVER_DESC "PCI/PCIe driver for chip ch365/ch367/ch368, etc." 52 | #define VERSION_DESC "V1.3 On 2023.07" 53 | 54 | #define CH36X_MAX_NUM 16 55 | #define CH36X_DRV_NAME "ch36xpci" 56 | 57 | #define CH365_VID 0x4348 // Vendor id 58 | #define CH365_DID 0x5049 // Device id 59 | #define CH367_VID 0x1C00 // Vendor id 60 | 61 | #define CH367_DID_SID_HIGH 0x5831 // Device id when SID high 62 | #define CH367_DID_SID_LOW 0x5830 // Device id when SID low 63 | #define CH367_SUB_VID 0x1C00 // Subsystem vendor id 64 | #define CH367_SUB_DID_SID_HIGH 0x5831 // Subsystem Vendor id when SID high 65 | #define CH367_SUB_DID_SID_LOW 0x5830 // Subsystem Device id when SID low 66 | 67 | #define CH368_VID 0x1C00 // Vendor id 68 | #define CH368_DID 0x5834 // Device id 69 | #define CH368_SUB_VID 0x1C00 // Subsystem Vendor id 70 | #define CH368_SUB_DID 0x5834 // Subsystem Device id 71 | 72 | #define SIZE_BYTE 0x01 73 | #define SIZE_WORD 0x02 74 | #define SIZE_DWORD 0x03 75 | 76 | #define TRIGGER_LOW 0xe0 77 | #define TRIGGER_HIGH 0xe4 78 | 79 | #define TRIGGER_RISING 0xe8 80 | #define TRIGGER_FALLING 0xec 81 | 82 | /* IOCTRL register bits */ 83 | #define CH365_IOCTRL_A15_BIT BIT(0) /* Set A15 */ 84 | #define CH365_IOCTRL_SYS_EX_BIT BIT(1) /* Set SYS_EX */ 85 | #define CH365_IOCTRL_INTA_BIT BIT(2) /* INT Active status */ 86 | 87 | /* MICSR register bits */ 88 | #define CH367_MICSR_GPO_BIT BIT(0) /* Set GPO */ 89 | #define CH367_MICSR_INTA_BIT BIT(2) /* INT Active status */ 90 | #define CH367_MICSR_INTS_BIT BIT(3) /* INT status */ 91 | #define CH367_MICSR_RSTO_BIT BIT(7) /* Set RSTO */ 92 | 93 | /* INTCR register bits */ 94 | #define CH367_INTCR_MSI_ENABLE_BIT BIT(0) /* MSI Enable */ 95 | #define CH367_INTCR_INT_ENABLE_BIT BIT(1) /* Global INT Enable */ 96 | #define CH367_INTCR_INT_POLAR_BIT BIT(2) /* Set INT Polar */ 97 | #define CH367_INTCR_INT_TYPE_BIT BIT(3) /* Set INT Type */ 98 | #define CH367_INTCR_INT_RETRY_BIT BIT(4) /* Set INT Retry */ 99 | 100 | /* GPOR register bits */ 101 | #define CH367_GPOR_SET_SDA_BIT BIT(0) /* Set SDA Value */ 102 | #define CH367_GPOR_SET_SCL_BIT BIT(1) /* Set SCL Value */ 103 | #define CH367_GPOR_SET_SCS_BIT BIT(2) /* Set SCS Value */ 104 | #define CH367_GPOR_ENABLE_WAKE_BIT BIT(5) /* Force Wakeup Support */ 105 | #define CH367_GPOR_SET_SDX_DIR_BIT BIT(6) /* Set SDX Direction */ 106 | #define CH367_GPOR_SET_SDX_BIT BIT(7) /* Set SDX Value */ 107 | 108 | /* SPICR register bits */ 109 | #define CH367_SPICR_SPI_status_BIT BIT(4) /* SPI Transfer Ongoing status */ 110 | #define CH367_SPICR_SPI_FREQ_BIT BIT(5) /* Set SPI Freq: 1->15.6MHz 0->31.3MHz */ 111 | #define CH367_SPICR_SPI_SLT_SDI_BIT BIT(6) /* Set SPI Data In Pin: 1->SDI 0->SDX */ 112 | #define CH367_SPICR_SPI_NEWTRAN_BIT BIT(7) /* Begin New Transfer After Read SPIDR */ 113 | 114 | #define CH365_STA_REG 0x42 115 | #define CH365_STA_ENABLE BIT(7) /* Global INT Enable */ 116 | 117 | enum CHIP_TYPE { 118 | CHIP_CH365 = 1, 119 | CHIP_CH367, 120 | CHIP_CH368 121 | }; 122 | 123 | enum INTMODE { 124 | INT_NONE = 0, 125 | INT_LOW, 126 | INT_HIGH, 127 | INT_RISING, 128 | INT_FALLING 129 | }; 130 | 131 | typedef struct _CH365_IO_REG { // CH365 IO space 132 | u8 mCh365IoPort[0xf0]; // 00H-EFH, 240 bytes standard IO bytes 133 | union { 134 | u16 mCh365MemAddr; // F0H Memory Interface: A15-A0 address setting register 135 | struct { 136 | u8 mCh365MemAddrL; // F0H Memory Interface: A7-A0 address setting register 137 | u8 mCh365MemAddrH; // F1H Memory Interface: A15-A8 address setting register 138 | }; 139 | }; 140 | u8 mCh365IoResv2; // F2H 141 | u8 mCh365MemData; // F3H Memory Interface: Memory data access register 142 | u8 mCh365I2cData; // F4H I2C Interface: I2C data access register 143 | u8 mCh365I2cCtrl; // F5H I2C Interface: I2C control and status register 144 | u8 mCh365I2cAddr; // F6H I2C Interface: I2C address setting register 145 | u8 mCh365I2cDev; // F7H I2C Interface: I2C device address and command register 146 | u8 mCh365IoCtrl; // F8H Control register, high 5 bits are read-only 147 | u8 mCh365IoBuf; // F9H Local data input buffer register 148 | u8 mCh365Speed; // FAH Speed control register 149 | u8 mCh365IoResv3; // FBH 150 | u8 mCh365IoTime; // FCH Hardware loop count register 151 | u8 mCh365IoResv4[3]; // FDH 152 | } mCH365_IO_REG, *mPCH365_IO_REG; 153 | 154 | typedef struct _CH365_MEM_REG { // CH365 Memory space 155 | u8 mCh365MemPort[0x8000]; // 0000H-7FFFH, 32768 bytes in total 156 | } mCH365_MEM_REG, *mPCH365_MEM_REG; 157 | 158 | typedef struct _CH367_IO_REG { // CH367 IO space 159 | u8 mCH367IoPort[0xE8]; // 00H-E7H, 232 bytes standard IO bytes 160 | u8 mCH367GPOR; // E8H General output register 161 | u8 mCH367GPVR; // E9H General variable register 162 | u8 mCH367GPIR; // EAH General input register 163 | u8 mCH367IntCtr; // EBH Interrupt control register 164 | union { 165 | u8 mCH367IoBuf8; // ECH 8-bit passive parallel interface data buffer 166 | u32 mCH367IoBuf32; // ECH 32-bit passive parallel interface data buffer 167 | }; 168 | union { 169 | u16 mCH368MemAddr; // F0H Memory Interface: A15-A0 address setting register 170 | struct { 171 | u8 mCH368MemAddrL; // F0H Memory Interface: A7-A0 address setting register 172 | union { 173 | u8 mCH368MemAddrH; // F1H Memory Interface: A15-A8 address setting register 174 | u8 mCH367GPOR2; // F1H General output register 2 175 | }; 176 | } ASR; 177 | }; 178 | u8 mCH367IORESV2; // F2H 179 | u8 mCH368MemData; // F3H Memory Interface: Memory data access register 180 | union { 181 | u8 mCH367Data8Sta; // F4H D7-D0 port status register 182 | u32 mCH367SData32Sta; // F4H D31-D0 port status register 183 | }; 184 | u8 mCH367status; // F8H Miscellaneous control and status register 185 | u8 mCH367IO_RESV3; // F9H 186 | u8 mCH367Speed; // FAH Speed control register 187 | u8 mCH367PDataCtrl; // FBH Passive parallel interface control register 188 | u8 mCH367IoTime; // FCH Hardware loop count register 189 | u8 mCH367SPICtrl; // FDH SPI control register 190 | u8 mCH367SPIData; // FEH SPI data register 191 | u8 mCH367IO_RESV4; // FFH 192 | } mCH367_IO_REG, *mPCH367_IO_REG; 193 | 194 | typedef struct _CH368_MEM_REG { // CH367 Memory space 195 | u8 mCH368MemPort[0x8000]; // 0000H-7FFFH, 32768 bytes in total 196 | } mCH368_MEM_REG, *mPCH368_MEM_REG; 197 | 198 | #define mMAX_buffer_LENGTH max(sizeof(mCH367_IO_REG), sizeof(mCH368_MEM_REG)) 199 | 200 | #define IOCTL_MAGIC 'P' 201 | #define CH36x_GET_IO_BASE_ADDR _IOR(IOCTL_MAGIC, 0x80, u16) 202 | #define CH36x_GET_MEM_BASE_ADDR _IOR(IOCTL_MAGIC, 0x81, u16) 203 | 204 | /* io/mem rw codes */ 205 | #define CH36x_READ_CONFIG_BYTE _IOR(IOCTL_MAGIC, 0x82, u16) 206 | #define CH36x_READ_CONFIG_WORD _IOR(IOCTL_MAGIC, 0x83, u16) 207 | #define CH36x_READ_CONFIG_DWORD _IOR(IOCTL_MAGIC, 0x84, u16) 208 | #define CH36x_WRITE_CONFIG_BYTE _IOW(IOCTL_MAGIC, 0x85, u16) 209 | #define CH36x_WRITE_CONFIG_WORD _IOW(IOCTL_MAGIC, 0x86, u16) 210 | #define CH36x_WRITE_CONFIG_DWORD _IOW(IOCTL_MAGIC, 0x87, u16) 211 | 212 | #define CH36x_READ_IO_BYTE _IOR(IOCTL_MAGIC, 0x88, u16) 213 | #define CH36x_READ_IO_WORD _IOR(IOCTL_MAGIC, 0x89, u16) 214 | #define CH36x_READ_IO_DWORD _IOR(IOCTL_MAGIC, 0x8a, u16) 215 | #define CH36x_WRITE_IO_BYTE _IOW(IOCTL_MAGIC, 0x8b, u16) 216 | #define CH36x_WRITE_IO_WORD _IOW(IOCTL_MAGIC, 0x8c, u16) 217 | #define CH36x_WRITE_IO_DWORD _IOW(IOCTL_MAGIC, 0x8d, u16) 218 | 219 | #define CH36x_READ_MEM_BYTE _IOR(IOCTL_MAGIC, 0x8e, u16) 220 | #define CH36x_READ_MEM_WORD _IOR(IOCTL_MAGIC, 0x8f, u16) 221 | #define CH36x_READ_MEM_DWORD _IOR(IOCTL_MAGIC, 0x90, u16) 222 | #define CH36x_WRITE_MEM_BYTE _IOW(IOCTL_MAGIC, 0x91, u16) 223 | #define CH36x_WRITE_MEM_WORD _IOW(IOCTL_MAGIC, 0x92, u16) 224 | #define CH36x_WRITE_MEM_DWORD _IOW(IOCTL_MAGIC, 0x93, u16) 225 | #define CH36x_READ_MEM_BLOCK _IOR(IOCTL_MAGIC, 0x94, u16) 226 | #define CH36x_WRITE_MEM_BLOCK _IOW(IOCTL_MAGIC, 0x95, u16) 227 | 228 | /* interrupt codes */ 229 | #define CH36x_ENABLE_INT _IOW(IOCTL_MAGIC, 0x96, u16) 230 | #define CH36x_DISABLE_INT _IOW(IOCTL_MAGIC, 0x97, u16) 231 | #define CH36x_GET_IRQ _IOR(IOCTL_MAGIC, 0xa0, u16) 232 | 233 | /* other codes */ 234 | #define CH36x_GET_CHIPTYPE _IOR(IOCTL_MAGIC, 0x98, u16) 235 | #define CH36x_GET_VERSION _IOR(IOCTL_MAGIC, 0x99, u16) 236 | #define CH36x_SET_STREAM _IOW(IOCTL_MAGIC, 0x9a, u16) 237 | #define CH36x_STREAM_SPI _IOWR(IOCTL_MAGIC, 0x9b, u16) 238 | #define CH36x_FLASH_LOCK _IOW(IOCTL_MAGIC, 0x9c, u16) 239 | #define CH36x_FLASH_ERASE _IOW(IOCTL_MAGIC, 0x9d, u16) 240 | #define CH36x_FLASH_READ _IOWR(IOCTL_MAGIC, 0x9e, u16) 241 | #define CH36x_FLASH_WRITE _IOW(IOCTL_MAGIC, 0x9f, u16) 242 | 243 | /* global varibles */ 244 | static unsigned char g_dev_count = 0; 245 | static struct class *ch36x_class = NULL; 246 | static struct list_head g_private_head; 247 | static int ch36x_major = 0x00; 248 | 249 | struct ch36x_dev { 250 | struct list_head ch36x_dev_list; 251 | struct pci_dev *ch36x_pdev; 252 | struct cdev cdev; 253 | dev_t ch36x_dev; 254 | enum CHIP_TYPE chiptype; 255 | unsigned long ioaddr; 256 | unsigned long iolen; 257 | void __iomem *memaddr; 258 | unsigned long memlen; 259 | int irq; 260 | char dev_file_name[20]; 261 | struct mutex io_mutex; 262 | enum INTMODE intmode; 263 | struct fasync_struct *fasync; 264 | u8 spimode; 265 | }; 266 | 267 | static int ch36x_cfg_read(int type, unsigned char offset, void *buf, struct pci_dev *pdev) 268 | { 269 | int retval = 0; 270 | u8 read_byte; 271 | u16 read_word; 272 | u32 read_dword; 273 | 274 | switch (type) { 275 | case SIZE_BYTE: 276 | pci_read_config_byte(pdev, offset, &read_byte); 277 | retval = put_user(read_byte, (u8 __user *)buf); 278 | break; 279 | case SIZE_WORD: 280 | pci_read_config_word(pdev, offset, &read_word); 281 | retval = put_user(read_word, (u16 __user *)buf); 282 | break; 283 | case SIZE_DWORD: 284 | pci_read_config_dword(pdev, offset, &read_dword); 285 | retval = put_user(read_dword, (u32 __user *)buf); 286 | break; 287 | default: 288 | return -EINVAL; 289 | } 290 | 291 | return retval; 292 | } 293 | 294 | static int ch36x_cfg_write(int type, unsigned char offset, void *buf, struct pci_dev *pdev) 295 | { 296 | int retval = 0; 297 | u8 write_byte; 298 | u16 write_word; 299 | u32 write_dword; 300 | 301 | switch (type) { 302 | case SIZE_BYTE: 303 | retval = get_user(write_byte, (u8 __user *)buf); 304 | if (retval) 305 | goto out; 306 | pci_write_config_byte(pdev, offset, write_byte); 307 | break; 308 | case SIZE_WORD: 309 | retval = get_user(write_word, (u16 __user *)buf); 310 | if (retval) 311 | goto out; 312 | pci_write_config_word(pdev, offset, write_word); 313 | break; 314 | case SIZE_DWORD: 315 | retval = get_user(write_dword, (u32 __user *)buf); 316 | if (retval) 317 | goto out; 318 | pci_write_config_dword(pdev, offset, write_dword); 319 | break; 320 | default: 321 | return -EINVAL; 322 | } 323 | 324 | out: 325 | return retval; 326 | } 327 | 328 | static int ch36x_io_read(int type, u8 offset, void *buf, struct ch36x_dev *ch36x_dev) 329 | { 330 | int retval = 0; 331 | u32 ioval; 332 | u8 regval; 333 | 334 | if (type == SIZE_WORD || type == SIZE_DWORD) { 335 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 336 | if (!(regval & BIT(6))) 337 | outb(regval | BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 338 | } else { 339 | if (offset != offsetof(mCH367_IO_REG, mCH367Speed)) { 340 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 341 | if (regval & BIT(6)) 342 | outb(regval & ~BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 343 | } 344 | } 345 | 346 | switch (type) { 347 | case SIZE_BYTE: 348 | ioval = inb(ch36x_dev->ioaddr + offset); 349 | retval = put_user(ioval, (u8 __user *)buf); 350 | break; 351 | case SIZE_WORD: 352 | ioval = inl(ch36x_dev->ioaddr + offset); 353 | retval = put_user(ioval, (u16 __user *)buf); 354 | break; 355 | case SIZE_DWORD: 356 | ioval = inl(ch36x_dev->ioaddr + offset); 357 | retval = put_user(ioval, (u32 __user *)buf); 358 | break; 359 | default: 360 | return -EINVAL; 361 | } 362 | 363 | return retval; 364 | } 365 | 366 | static int ch36x_io_write(int type, u8 offset, void *buf, struct ch36x_dev *ch36x_dev) 367 | { 368 | int retval = 0; 369 | u8 write_byte; 370 | u16 write_word; 371 | u32 write_dword; 372 | u8 regval; 373 | 374 | if (type == SIZE_WORD || type == SIZE_DWORD) { 375 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 376 | if (!(regval & BIT(6))) 377 | outb(regval | BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 378 | } else { 379 | if (offset != offsetof(mCH367_IO_REG, mCH367Speed)) { 380 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 381 | if (regval & BIT(6)) 382 | outb(regval & ~BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 383 | } 384 | } 385 | 386 | switch (type) { 387 | case SIZE_BYTE: 388 | retval = get_user(write_byte, (u8 __user *)buf); 389 | if (retval) 390 | goto out; 391 | outb(write_byte, ch36x_dev->ioaddr + offset); 392 | break; 393 | case SIZE_WORD: 394 | retval = get_user(write_word, (u16 __user *)buf); 395 | if (retval) 396 | goto out; 397 | outl(write_word | 0xffff0000, ch36x_dev->ioaddr + offset); 398 | break; 399 | case SIZE_DWORD: 400 | retval = get_user(write_dword, (u32 __user *)buf); 401 | if (retval) 402 | goto out; 403 | outl(write_dword, ch36x_dev->ioaddr + offset); 404 | break; 405 | default: 406 | return -EINVAL; 407 | } 408 | out: 409 | return retval; 410 | } 411 | 412 | static int ch36x_mmio_read(int type, u16 offset, void *buf, struct ch36x_dev *ch36x_dev) 413 | { 414 | int retval = 0; 415 | u32 ioval; 416 | u8 regval; 417 | 418 | if (type == SIZE_WORD || type == SIZE_DWORD) { 419 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 420 | if (!(regval & BIT(6))) 421 | outb(regval | BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 422 | } else { 423 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 424 | if (regval & BIT(6)) 425 | outb(regval & ~BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 426 | } 427 | 428 | switch (type) { 429 | case SIZE_BYTE: 430 | ioval = ioread8((u8 __iomem *)(ch36x_dev->memaddr) + offset); 431 | retval = put_user(ioval, (u8 __user *)buf); 432 | break; 433 | case SIZE_WORD: 434 | ioval = ioread32((u8 __iomem *)(ch36x_dev->memaddr) + offset); 435 | retval = put_user(ioval, (u16 __user *)buf); 436 | break; 437 | case SIZE_DWORD: 438 | ioval = ioread32((u8 __iomem *)(ch36x_dev->memaddr) + offset); 439 | retval = put_user(ioval, (u32 __user *)buf); 440 | break; 441 | default: 442 | return -EINVAL; 443 | } 444 | 445 | return retval; 446 | } 447 | 448 | static int ch36x_mmio_write(int type, u16 offset, void *buf, struct ch36x_dev *ch36x_dev) 449 | { 450 | int retval = 0; 451 | u8 write_byte; 452 | u16 write_word; 453 | u32 write_dword; 454 | u8 regval; 455 | 456 | if (type == SIZE_WORD || type == SIZE_DWORD) { 457 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 458 | if (!(regval & BIT(6))) 459 | outb(regval | BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 460 | } else { 461 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 462 | if (regval & BIT(6)) 463 | outb(regval & ~BIT(6), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367Speed)); 464 | } 465 | 466 | switch (type) { 467 | case SIZE_BYTE: 468 | retval = get_user(write_byte, (u8 __user *)buf); 469 | if (retval) 470 | goto out; 471 | iowrite8(write_byte, (u8 __iomem *)(ch36x_dev->memaddr) + offset); 472 | break; 473 | case SIZE_WORD: 474 | retval = get_user(write_word, (u16 __user *)buf); 475 | if (retval) 476 | goto out; 477 | iowrite32(write_word | 0xffff0000, (u8 __iomem *)(ch36x_dev->memaddr) + offset); 478 | break; 479 | case SIZE_DWORD: 480 | retval = get_user(write_dword, (u32 __user *)buf); 481 | if (retval) 482 | goto out; 483 | iowrite32(write_dword, (u8 __iomem *)(ch36x_dev->memaddr) + offset); 484 | break; 485 | default: 486 | return -EINVAL; 487 | } 488 | 489 | out: 490 | return retval; 491 | } 492 | 493 | static int ch36x_mem_read_block(u8 type, u16 offset, void *buf, u32 len, struct ch36x_dev *ch36x_dev) 494 | { 495 | int retval = 0; 496 | u32 ioval; 497 | int times; 498 | int i; 499 | u8 *tbuf; 500 | u32 rindex = 0; 501 | 502 | if ((type == SIZE_DWORD) && (len % 4 != 0)) 503 | return -EINVAL; 504 | 505 | times = len / 4; 506 | 507 | tbuf = kmalloc(len, GFP_KERNEL); 508 | if (!tbuf) 509 | return -ENOMEM; 510 | 511 | if (type == SIZE_DWORD) { 512 | for (i = 0; i < times; i++) { 513 | ioval = ioread32((u8 __iomem *)(ch36x_dev->memaddr) + offset + rindex); 514 | *(u32 *)(tbuf + rindex) = ioval; 515 | rindex += 4; 516 | } 517 | } else { 518 | for (i = 0; i < len; i++) { 519 | *(tbuf + rindex) = ioread8((u8 __iomem *)(ch36x_dev->memaddr) + offset + rindex); 520 | rindex += 1; 521 | } 522 | } 523 | 524 | retval = copy_to_user((char __user *)buf, tbuf, len); 525 | 526 | kfree(tbuf); 527 | return retval; 528 | } 529 | 530 | static int ch36x_mem_write_block(u8 type, u16 offset, void *buf, u32 len, struct ch36x_dev *ch36x_dev) 531 | { 532 | int retval = 0; 533 | u32 ioval; 534 | int times; 535 | int i; 536 | u8 *tbuf; 537 | u32 rindex = 0; 538 | 539 | if ((type == SIZE_DWORD) && (len % 4 != 0)) 540 | return -EINVAL; 541 | 542 | times = len / 4; 543 | 544 | tbuf = kmalloc(len, GFP_KERNEL); 545 | if (!tbuf) 546 | return -ENOMEM; 547 | 548 | retval = copy_from_user(tbuf, (char __user *)buf, len); 549 | if (retval) 550 | goto exit; 551 | 552 | if (type == SIZE_DWORD) { 553 | for (i = 0; i < times; i++) { 554 | ioval = *(u32 *)(tbuf + rindex); 555 | iowrite32(ioval, (u8 __iomem *)(ch36x_dev->memaddr) + offset + rindex); 556 | rindex += 4; 557 | } 558 | } else { 559 | for (i = 0; i < len; i++) { 560 | iowrite8(*(tbuf + rindex), (u8 __iomem *)(ch36x_dev->memaddr) + offset + rindex); 561 | rindex += 1; 562 | } 563 | } 564 | exit: 565 | kfree(tbuf); 566 | return retval; 567 | } 568 | 569 | static void ch36x_start_spi_data_in(struct ch36x_dev *ch36x_dev, u8 regGPOR) 570 | { 571 | if (!(ch36x_dev->spimode & BIT(1))) 572 | outb(regGPOR & 0x39, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 573 | inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 574 | } 575 | 576 | static bool ch36x_start_spi(struct ch36x_dev *ch36x_dev, u8 *regGPOR) 577 | { 578 | u8 regval; 579 | 580 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 581 | if (ch36x_dev->spimode & BIT(0)) { 582 | if (ch36x_dev->spimode & BIT(1)) 583 | outb(CH367_SPICR_SPI_NEWTRAN_BIT | CH367_SPICR_SPI_FREQ_BIT | CH367_SPICR_SPI_SLT_SDI_BIT, 584 | ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 585 | else 586 | outb(CH367_SPICR_SPI_NEWTRAN_BIT | CH367_SPICR_SPI_FREQ_BIT, 587 | ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 588 | } else { 589 | if (ch36x_dev->spimode & BIT(1)) 590 | outb(CH367_SPICR_SPI_NEWTRAN_BIT | CH367_SPICR_SPI_SLT_SDI_BIT, 591 | ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 592 | else 593 | outb(CH367_SPICR_SPI_NEWTRAN_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 594 | } 595 | 596 | *regGPOR = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 597 | if (!(*regGPOR & CH367_GPOR_SET_SCS_BIT)) 598 | outb(*regGPOR | CH367_GPOR_SET_SCS_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 599 | outb((*regGPOR & 0x39) | CH367_GPOR_SET_SDX_DIR_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 600 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 601 | if (regval & CH367_GPOR_SET_SCS_BIT) 602 | return false; 603 | 604 | return true; 605 | } 606 | 607 | static bool ch36x_stop_spi(struct ch36x_dev *ch36x_dev, u8 regGPOR) 608 | { 609 | u8 regval; 610 | 611 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 612 | outb(regval & CH367_SPICR_SPI_FREQ_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPICtrl)); 613 | outb((regGPOR & 0x39) | CH367_GPOR_SET_SDX_BIT | CH367_GPOR_SET_SCS_BIT, 614 | ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 615 | regval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 616 | if (!(regval & CH367_GPOR_SET_SCS_BIT)) 617 | return false; 618 | 619 | return true; 620 | } 621 | 622 | static int ch36x_stream_spi(struct ch36x_dev *ch36x_dev, void *ibuf, u32 ilen, void *obuf, u32 olen) 623 | { 624 | int retval = -1; 625 | char *buffer; 626 | u8 regGPOR; 627 | int i; 628 | 629 | buffer = kmalloc(max(ilen, olen), GFP_KERNEL); 630 | if (!buffer) { 631 | retval = -ENOMEM; 632 | goto error_mem; 633 | } 634 | retval = copy_from_user((char *)buffer, (char __user *)ibuf, ilen); 635 | if (retval) 636 | goto error; 637 | 638 | if (!ch36x_start_spi(ch36x_dev, ®GPOR)) { 639 | retval = -EFAULT; 640 | goto error; 641 | } 642 | for (i = 0; i < ilen; i++) 643 | outb(*(buffer + i), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 644 | 645 | if (olen) { 646 | ch36x_start_spi_data_in(ch36x_dev, regGPOR); 647 | for (i = 0; i < olen; i++) 648 | *(buffer + i) = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 649 | } 650 | ch36x_stop_spi(ch36x_dev, regGPOR); 651 | 652 | retval = copy_to_user((char __user *)obuf, buffer, olen); 653 | if (retval) 654 | goto error; 655 | 656 | error: 657 | kfree(buffer); 658 | error_mem: 659 | return retval; 660 | } 661 | 662 | static bool ch36x_flash_wait(struct ch36x_dev *ch36x_dev) 663 | { 664 | u8 status; 665 | u32 i = 0; 666 | u8 regGPOR; 667 | 668 | do { 669 | if (!ch36x_start_spi(ch36x_dev, ®GPOR)) 670 | return false; 671 | outb(0x05, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 672 | ch36x_start_spi_data_in(ch36x_dev, regGPOR); 673 | status = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 674 | ch36x_stop_spi(ch36x_dev, regGPOR); 675 | if (status & 0x01) { 676 | if (++i > 100000) 677 | return false; 678 | } 679 | } while (status & 0x01); 680 | 681 | return true; 682 | } 683 | 684 | static bool ch36x_flash_we(struct ch36x_dev *ch36x_dev) 685 | { 686 | u8 regGPOR; 687 | 688 | if (!ch36x_start_spi(ch36x_dev, ®GPOR)) 689 | return false; 690 | outb(0x06, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 691 | 692 | return ch36x_stop_spi(ch36x_dev, regGPOR); 693 | } 694 | 695 | static u8 ch36x_flash_id(struct ch36x_dev *ch36x_dev) 696 | { 697 | u8 flashID; 698 | u8 regGPOR; 699 | 700 | if (!ch36x_start_spi(ch36x_dev, ®GPOR)) { 701 | flashID = 0xff; 702 | return flashID; 703 | } 704 | outb(0x90, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 705 | outb(0x00, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 706 | outb(0x00, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 707 | outb(0x00, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 708 | ch36x_start_spi_data_in(ch36x_dev, regGPOR); 709 | flashID = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 710 | ch36x_stop_spi(ch36x_dev, regGPOR); 711 | 712 | return flashID; 713 | } 714 | 715 | static bool ch36x_flash_lock(struct ch36x_dev *ch36x_dev, u8 wrLock) 716 | { 717 | u8 flashID, regData; 718 | u8 regGPOR; 719 | 720 | flashID = ch36x_flash_id(ch36x_dev); 721 | if (flashID == 0xff) 722 | return false; 723 | 724 | if (wrLock == 0xFF) { 725 | regData = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 726 | regData |= 0x08; 727 | outb(regData, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367GPOR)); 728 | return true; 729 | } else { 730 | if (!(ch36x_flash_we(ch36x_dev))) 731 | return false; 732 | 733 | if (flashID == 0xBF) { 734 | ch36x_start_spi(ch36x_dev, ®GPOR); 735 | outb(0x50, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 736 | ch36x_stop_spi(ch36x_dev, regGPOR); 737 | } 738 | ch36x_start_spi(ch36x_dev, ®GPOR); 739 | outb(0x01, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 740 | outb(wrLock, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 741 | ch36x_stop_spi(ch36x_dev, regGPOR); 742 | 743 | return ch36x_flash_wait(ch36x_dev); 744 | } 745 | } 746 | 747 | static bool ch36x_flash_read(struct ch36x_dev *ch36x_dev, u32 startaddr, void *buf, u32 len) 748 | { 749 | u32 i = 0; 750 | u8 regGPOR; 751 | char *buffer; 752 | 753 | if (len == 0) 754 | return false; 755 | 756 | buffer = kmalloc(len, GFP_KERNEL); 757 | if (!buffer) 758 | return false; 759 | 760 | if (!ch36x_start_spi(ch36x_dev, ®GPOR)) { 761 | goto out; 762 | } 763 | 764 | outb(0x03, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 765 | outb((u8)(startaddr >> 16 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 766 | outb((u8)(startaddr >> 8 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 767 | outb((u8)(startaddr & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 768 | ch36x_start_spi_data_in(ch36x_dev, regGPOR); 769 | 770 | for (i = 0; i < len; i++) { 771 | buffer[i] = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 772 | } 773 | if (copy_to_user((char __user *)buf, buffer, len)) { 774 | goto out; 775 | } 776 | 777 | kfree(buffer); 778 | 779 | return ch36x_stop_spi(ch36x_dev, regGPOR); 780 | 781 | out: 782 | kfree(buffer); 783 | return false; 784 | } 785 | 786 | static bool ch36x_flash_erase(struct ch36x_dev *ch36x_dev, u32 startaddr, u32 len) 787 | { 788 | u32 i, flashID; 789 | u8 regGPOR; 790 | 791 | if (len == 0) 792 | return false; 793 | flashID = ch36x_flash_id(ch36x_dev); 794 | if (flashID == 0xff) 795 | return false; 796 | 797 | if ((flashID != 0XBF) && (startaddr & 0x7FFF) == 0) { 798 | while (len >= 0x8000) { 799 | if (!(ch36x_flash_we(ch36x_dev))) 800 | return false; 801 | ch36x_start_spi(ch36x_dev, ®GPOR); 802 | outb(0xD8, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 803 | outb((u8)(startaddr >> 16 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 804 | outb((u8)(startaddr >> 8 & 0xF0), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 805 | outb(0x00, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 806 | ch36x_stop_spi(ch36x_dev, regGPOR); 807 | ch36x_flash_wait(ch36x_dev); 808 | startaddr += 0x8000; 809 | len -= 0x8000; 810 | } 811 | } 812 | for (i = 0; i < len; i += 4096) { 813 | if (!(ch36x_flash_we(ch36x_dev))) 814 | return false; 815 | ch36x_start_spi(ch36x_dev, ®GPOR); 816 | outb(0x20, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 817 | outb((u8)(startaddr >> 16 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 818 | outb((u8)(startaddr >> 8 & 0xF0), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 819 | outb(0x00, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 820 | ch36x_stop_spi(ch36x_dev, regGPOR); 821 | ch36x_flash_wait(ch36x_dev); 822 | startaddr += 0x1000; 823 | } 824 | return true; 825 | } 826 | 827 | static bool ch36x_flash_write(struct ch36x_dev *ch36x_dev, u32 startaddr, void *buf, u32 len) 828 | { 829 | u8 flashID, j; 830 | u32 i; 831 | u8 regGPOR; 832 | u8 *buffer; 833 | int retval; 834 | 835 | if (len == 0) 836 | return false; 837 | 838 | buffer = kmalloc(len, GFP_KERNEL); 839 | if (!buffer) 840 | return -false; 841 | 842 | retval = copy_from_user(buffer, (char __user *)buf, len); 843 | if (retval) 844 | goto out; 845 | 846 | flashID = ch36x_flash_id(ch36x_dev); 847 | if (flashID == 0xff) 848 | goto out; 849 | 850 | if (flashID == 0xBF) { 851 | if (!(ch36x_flash_we(ch36x_dev))) 852 | goto out; 853 | ch36x_start_spi(ch36x_dev, ®GPOR); 854 | outb(0xAF, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 855 | outb((u8)(startaddr >> 16 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 856 | outb((u8)(startaddr >> 8 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 857 | j = (u8)(startaddr & 0xFF); 858 | for (i = 0; i < len; i++) { 859 | if (i) { 860 | ch36x_start_spi(ch36x_dev, ®GPOR); 861 | j = 175; 862 | } 863 | outb(j, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 864 | outb(buffer[i], ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 865 | ch36x_stop_spi(ch36x_dev, regGPOR); 866 | ch36x_flash_wait(ch36x_dev); 867 | } 868 | ch36x_start_spi(ch36x_dev, ®GPOR); 869 | outb(0x04, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 870 | retval = ch36x_stop_spi(ch36x_dev, regGPOR); 871 | if (retval == false) 872 | goto out; 873 | } else { 874 | for (i = 0; i < len;) { 875 | if (!(ch36x_flash_we(ch36x_dev))) 876 | goto out; 877 | ch36x_start_spi(ch36x_dev, ®GPOR); 878 | 879 | outb(0x02, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 880 | outb((u8)(startaddr >> 16 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 881 | outb((u8)(startaddr >> 8 & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 882 | outb((u8)(startaddr & 0xFF), ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 883 | do { 884 | outb(buffer[i], ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367SPIData)); 885 | startaddr++; 886 | if (++i >= len) 887 | break; 888 | } while (startaddr & 0xFF); // 256 bytes per page 889 | ch36x_stop_spi(ch36x_dev, regGPOR); 890 | ch36x_flash_wait(ch36x_dev); 891 | } 892 | } 893 | 894 | return true; 895 | 896 | out: 897 | kfree(buffer); 898 | return false; 899 | } 900 | 901 | static irqreturn_t ch36x_isr(int irq, void *dev_id) 902 | { 903 | unsigned char intval; 904 | struct ch36x_dev *ch36x_dev = (struct ch36x_dev *)dev_id; 905 | 906 | dev_vdbg(&ch36x_dev->ch36x_pdev->dev, "%s occurs\n", __func__); 907 | if (ch36x_dev->chiptype == CHIP_CH365) { 908 | intval = inb(ch36x_dev->ioaddr + offsetof(mCH365_IO_REG, mCh365IoCtrl)); 909 | if (!(intval & CH365_IOCTRL_INTA_BIT)) 910 | return IRQ_NONE; 911 | } else { 912 | intval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367status)); 913 | switch (ch36x_dev->intmode) { 914 | case INT_RISING: 915 | case INT_FALLING: 916 | if (!(intval & CH367_MICSR_INTA_BIT)) 917 | return IRQ_NONE; 918 | break; 919 | case INT_HIGH: 920 | if (!(intval & CH367_MICSR_INTS_BIT)) 921 | return IRQ_NONE; 922 | break; 923 | case INT_LOW: 924 | if (intval & CH367_MICSR_INTS_BIT) 925 | return IRQ_NONE; 926 | break; 927 | default: 928 | return IRQ_NONE; 929 | } 930 | } 931 | kill_fasync(&ch36x_dev->fasync, SIGIO, POLL_IN); 932 | 933 | /* interrupt status clear */ 934 | if (ch36x_dev->chiptype == CHIP_CH365) { 935 | outb(intval & ~CH365_IOCTRL_INTA_BIT, ch36x_dev->ioaddr + offsetof(mCH365_IO_REG, mCh365IoCtrl)); 936 | } else { 937 | outb(intval & ~CH367_MICSR_INTA_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367status)); 938 | } 939 | 940 | return IRQ_HANDLED; 941 | } 942 | 943 | static void ch36x_enable_interrupts(struct ch36x_dev *ch36x_dev, enum INTMODE mode) 944 | { 945 | u8 ctrlval; 946 | u8 intval; 947 | 948 | if (ch36x_dev->chiptype == CHIP_CH365) { 949 | pci_read_config_byte(ch36x_dev->ch36x_pdev, CH365_STA_REG, &ctrlval); 950 | pci_write_config_byte(ch36x_dev->ch36x_pdev, CH365_STA_REG, ctrlval | CH365_STA_ENABLE); 951 | } else { 952 | ctrlval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 953 | switch (mode) { 954 | case INT_LOW: 955 | outb(ctrlval | TRIGGER_LOW, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 956 | break; 957 | case INT_HIGH: 958 | outb(ctrlval | TRIGGER_HIGH, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 959 | break; 960 | case INT_RISING: 961 | outb(ctrlval | TRIGGER_RISING, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 962 | break; 963 | case INT_FALLING: 964 | outb(ctrlval | TRIGGER_FALLING, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 965 | break; 966 | default: 967 | break; 968 | } 969 | ctrlval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 970 | outb(ctrlval | CH367_INTCR_INT_ENABLE_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 971 | intval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367status)); 972 | outb(intval & ~CH367_MICSR_INTA_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367status)); 973 | } 974 | ch36x_dev->intmode = mode; 975 | } 976 | 977 | static void ch36x_disable_interrupts(struct ch36x_dev *ch36x_dev) 978 | { 979 | u8 ctrlval; 980 | u8 intval; 981 | 982 | if (ch36x_dev->chiptype == CHIP_CH365) { 983 | pci_read_config_byte(ch36x_dev->ch36x_pdev, CH365_STA_REG, &ctrlval); 984 | pci_write_config_byte(ch36x_dev->ch36x_pdev, CH365_STA_REG, ctrlval & ~CH365_STA_ENABLE); 985 | } else { 986 | ctrlval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 987 | outb(ctrlval & ~(CH367_INTCR_INT_POLAR_BIT | CH367_INTCR_INT_TYPE_BIT | CH367_INTCR_INT_ENABLE_BIT), 988 | ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367IntCtr)); 989 | intval = inb(ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367status)); 990 | outb(intval & ~CH367_MICSR_INTA_BIT, ch36x_dev->ioaddr + offsetof(mCH367_IO_REG, mCH367status)); 991 | } 992 | ch36x_dev->intmode = INT_NONE; 993 | } 994 | 995 | static int ch36x_fops_open(struct inode *inode, struct file *fp) 996 | { 997 | unsigned int minor = iminor(inode); 998 | struct list_head *pos; 999 | struct list_head *pos_tmp; 1000 | struct ch36x_dev *ch36x_dev; 1001 | 1002 | list_for_each_safe(pos, pos_tmp, &g_private_head) { 1003 | ch36x_dev = list_entry(pos, struct ch36x_dev, ch36x_dev_list); 1004 | if (minor == MINOR(ch36x_dev->ch36x_dev)) { 1005 | break; 1006 | } 1007 | } 1008 | if (pos == &g_private_head) { 1009 | pr_err("%s Can't find minor:%d line:%d", __func__, minor, __LINE__); 1010 | return -ENODEV; 1011 | } 1012 | return 0; 1013 | } 1014 | 1015 | static int ch36x_fops_release(struct inode *inode, struct file *fp) 1016 | { 1017 | unsigned int minor = iminor(inode); 1018 | struct list_head *pos; 1019 | struct list_head *pos_tmp; 1020 | struct ch36x_dev *ch36x_dev; 1021 | 1022 | list_for_each_safe(pos, pos_tmp, &g_private_head) { 1023 | ch36x_dev = list_entry(pos, struct ch36x_dev, ch36x_dev_list); 1024 | if (minor == MINOR(ch36x_dev->ch36x_dev)) { 1025 | break; 1026 | } 1027 | } 1028 | if (pos == &g_private_head) { 1029 | pr_err("%s Can't find minor:%d line:%d", __func__, minor, __LINE__); 1030 | return -ENODEV; 1031 | } 1032 | if (ch36x_dev->intmode) 1033 | ch36x_disable_interrupts(ch36x_dev); 1034 | 1035 | return 0; 1036 | } 1037 | 1038 | static ssize_t ch36x_fops_read(struct file *fp, char __user *buf, size_t len, loff_t *off) 1039 | { 1040 | return 0; 1041 | } 1042 | 1043 | static ssize_t ch36x_fops_write(struct file *fp, const char __user *buf, size_t len, loff_t *off) 1044 | { 1045 | return 0; 1046 | } 1047 | 1048 | static int ch36x_fops_ioctl_do(struct ch36x_dev *ch36x_dev, unsigned int cmd, unsigned long ch36x_arg) 1049 | { 1050 | int retval = 0; 1051 | unsigned long arg1; 1052 | unsigned long arg2; 1053 | unsigned long arg3; 1054 | unsigned long arg4; 1055 | 1056 | switch (cmd) { 1057 | case CH36x_GET_CHIPTYPE: 1058 | retval = put_user((unsigned long)ch36x_dev->chiptype, (long __user *)ch36x_arg); 1059 | break; 1060 | case CH36x_GET_VERSION: 1061 | retval = copy_to_user((char __user *)ch36x_arg, (char *)VERSION_DESC, strlen(VERSION_DESC)); 1062 | break; 1063 | case CH36x_GET_IRQ: 1064 | retval = put_user((unsigned long)ch36x_dev->irq, (long __user *)ch36x_arg); 1065 | break; 1066 | case CH36x_ENABLE_INT: 1067 | get_user(arg1, (long __user *)ch36x_arg); 1068 | ch36x_enable_interrupts(ch36x_dev, arg1); 1069 | break; 1070 | case CH36x_DISABLE_INT: 1071 | ch36x_disable_interrupts(ch36x_dev); 1072 | break; 1073 | case CH36x_GET_IO_BASE_ADDR: 1074 | retval = put_user(ch36x_dev->ioaddr, (long __user *)ch36x_arg); 1075 | break; 1076 | case CH36x_GET_MEM_BASE_ADDR: 1077 | retval = put_user((unsigned long)ch36x_dev->memaddr, (long __user *)ch36x_arg); 1078 | break; 1079 | case CH36x_READ_CONFIG_BYTE: 1080 | get_user(arg1, (u8 __user *)ch36x_arg); 1081 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1082 | retval = ch36x_cfg_read(SIZE_BYTE, arg1, (void *)arg2, ch36x_dev->ch36x_pdev); 1083 | break; 1084 | case CH36x_READ_CONFIG_WORD: 1085 | get_user(arg1, (u8 __user *)ch36x_arg); 1086 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1087 | retval = ch36x_cfg_read(SIZE_WORD, arg1, (void *)arg2, ch36x_dev->ch36x_pdev); 1088 | break; 1089 | case CH36x_READ_CONFIG_DWORD: 1090 | get_user(arg1, (u8 __user *)ch36x_arg); 1091 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1092 | retval = ch36x_cfg_read(SIZE_DWORD, arg1, (void *)arg2, ch36x_dev->ch36x_pdev); 1093 | break; 1094 | case CH36x_WRITE_CONFIG_BYTE: 1095 | get_user(arg1, (u8 __user *)ch36x_arg); 1096 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1097 | retval = ch36x_cfg_write(SIZE_BYTE, arg1, (void *)arg2, ch36x_dev->ch36x_pdev); 1098 | break; 1099 | case CH36x_WRITE_CONFIG_WORD: 1100 | get_user(arg1, (u8 __user *)ch36x_arg); 1101 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1102 | retval = ch36x_cfg_write(SIZE_WORD, arg1, (void *)arg2, ch36x_dev->ch36x_pdev); 1103 | break; 1104 | case CH36x_WRITE_CONFIG_DWORD: 1105 | get_user(arg1, (u8 __user *)ch36x_arg); 1106 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1107 | retval = ch36x_cfg_write(SIZE_DWORD, arg1, (void *)arg2, ch36x_dev->ch36x_pdev); 1108 | break; 1109 | case CH36x_READ_IO_BYTE: 1110 | get_user(arg1, (u8 __user *)ch36x_arg); 1111 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1112 | retval = ch36x_io_read(SIZE_BYTE, arg1, (void *)arg2, ch36x_dev); 1113 | break; 1114 | case CH36x_READ_IO_WORD: 1115 | get_user(arg1, (u8 __user *)ch36x_arg); 1116 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1117 | retval = ch36x_io_read(SIZE_WORD, arg1, (void *)arg2, ch36x_dev); 1118 | break; 1119 | case CH36x_READ_IO_DWORD: 1120 | get_user(arg1, (u8 __user *)ch36x_arg); 1121 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1122 | retval = ch36x_io_read(SIZE_DWORD, arg1, (void *)arg2, ch36x_dev); 1123 | break; 1124 | case CH36x_WRITE_IO_BYTE: 1125 | get_user(arg1, (u8 __user *)ch36x_arg); 1126 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1127 | retval = ch36x_io_write(SIZE_BYTE, arg1, (void *)arg2, ch36x_dev); 1128 | break; 1129 | case CH36x_WRITE_IO_WORD: 1130 | get_user(arg1, (u8 __user *)ch36x_arg); 1131 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1132 | retval = ch36x_io_write(SIZE_WORD, arg1, (void *)arg2, ch36x_dev); 1133 | break; 1134 | case CH36x_WRITE_IO_DWORD: 1135 | get_user(arg1, (u8 __user *)ch36x_arg); 1136 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 1); 1137 | retval = ch36x_io_write(SIZE_DWORD, arg1, (void *)arg2, ch36x_dev); 1138 | break; 1139 | case CH36x_READ_MEM_BYTE: 1140 | get_user(arg1, (u16 __user *)ch36x_arg); 1141 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 2); 1142 | retval = ch36x_mmio_read(SIZE_BYTE, arg1, (void *)arg2, ch36x_dev); 1143 | break; 1144 | case CH36x_READ_MEM_WORD: 1145 | get_user(arg1, (u16 __user *)ch36x_arg); 1146 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 2); 1147 | retval = ch36x_mmio_read(SIZE_WORD, arg1, (void *)arg2, ch36x_dev); 1148 | break; 1149 | case CH36x_READ_MEM_DWORD: 1150 | get_user(arg1, (u16 __user *)ch36x_arg); 1151 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 2); 1152 | retval = ch36x_mmio_read(SIZE_DWORD, arg1, (void *)arg2, ch36x_dev); 1153 | break; 1154 | case CH36x_WRITE_MEM_BYTE: 1155 | get_user(arg1, (u16 __user *)ch36x_arg); 1156 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 2); 1157 | retval = ch36x_mmio_write(SIZE_BYTE, arg1, (void *)arg2, ch36x_dev); 1158 | break; 1159 | case CH36x_WRITE_MEM_WORD: 1160 | get_user(arg1, (u16 __user *)ch36x_arg); 1161 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 2); 1162 | retval = ch36x_mmio_write(SIZE_WORD, arg1, (void *)arg2, ch36x_dev); 1163 | break; 1164 | case CH36x_WRITE_MEM_DWORD: 1165 | get_user(arg1, (u16 __user *)ch36x_arg); 1166 | arg2 = (unsigned long)((u8 __user *)ch36x_arg + 2); 1167 | retval = ch36x_mmio_write(SIZE_DWORD, arg1, (void *)arg2, ch36x_dev); 1168 | break; 1169 | case CH36x_READ_MEM_BLOCK: 1170 | get_user(arg1, (u8 __user *)ch36x_arg); 1171 | get_user(arg2, (u16 __user *)((u8 *)ch36x_arg + 1)); 1172 | get_user(arg3, (u32 __user *)((u8 *)ch36x_arg + 3)); 1173 | arg4 = (unsigned long)((u8 __user *)ch36x_arg + 7); 1174 | retval = ch36x_mem_read_block(arg1, arg2, (void *)arg4, arg3, ch36x_dev); 1175 | break; 1176 | case CH36x_WRITE_MEM_BLOCK: 1177 | get_user(arg1, (u8 __user *)ch36x_arg); 1178 | get_user(arg2, (u16 __user *)((u8 *)ch36x_arg + 1)); 1179 | get_user(arg3, (u32 __user *)((u8 *)ch36x_arg + 3)); 1180 | arg4 = (unsigned long)((u8 __user *)ch36x_arg + 7); 1181 | retval = ch36x_mem_write_block(arg1, arg2, (void *)arg4, arg3, ch36x_dev); 1182 | break; 1183 | case CH36x_SET_STREAM: 1184 | get_user(arg1, (u8 __user *)ch36x_arg); 1185 | ch36x_dev->spimode = arg1; 1186 | break; 1187 | case CH36x_STREAM_SPI: 1188 | get_user(arg1, (u32 __user *)ch36x_arg); 1189 | get_user(arg2, ((u32 __user *)ch36x_arg + 1)); 1190 | arg3 = (unsigned long)((u8 __user *)ch36x_arg + 8); 1191 | arg4 = (unsigned long)((u8 __user *)ch36x_arg + 8 + mMAX_buffer_LENGTH); 1192 | retval = ch36x_stream_spi(ch36x_dev, (void *)arg3, arg1, (void *)arg4, arg2); 1193 | break; 1194 | case CH36x_FLASH_LOCK: 1195 | get_user(arg1, (u8 __user *)ch36x_arg); 1196 | if (ch36x_flash_lock(ch36x_dev, (u8)arg1)) 1197 | retval = 0; 1198 | else 1199 | retval = -EFAULT; 1200 | break; 1201 | case CH36x_FLASH_ERASE: 1202 | get_user(arg1, (u32 __user *)ch36x_arg); 1203 | get_user(arg2, ((u32 __user *)ch36x_arg + 1)); 1204 | if (ch36x_flash_erase(ch36x_dev, arg1, arg2)) 1205 | retval = 0; 1206 | else 1207 | retval = -EFAULT; 1208 | break; 1209 | 1210 | case CH36x_FLASH_READ: 1211 | get_user(arg1, (u32 __user *)ch36x_arg); 1212 | get_user(arg2, ((u32 __user *)ch36x_arg + 1)); 1213 | arg3 = (unsigned long)((u32 __user *)ch36x_arg + 2); 1214 | if (ch36x_flash_read(ch36x_dev, arg1, (char __user *)arg3, arg2)) 1215 | retval = 0; 1216 | else 1217 | retval = -EFAULT; 1218 | break; 1219 | case CH36x_FLASH_WRITE: 1220 | get_user(arg1, (u32 __user *)ch36x_arg); 1221 | get_user(arg2, ((u32 __user *)ch36x_arg + 1)); 1222 | arg3 = (unsigned long)((u32 __user *)ch36x_arg + 2); 1223 | if (ch36x_flash_write(ch36x_dev, arg1, (char __user *)arg3, arg2)) 1224 | retval = 0; 1225 | else 1226 | retval = -EFAULT; 1227 | break; 1228 | default: 1229 | return -EINVAL; 1230 | } 1231 | 1232 | return retval; 1233 | } 1234 | 1235 | static long ch36x_fops_ioctl(struct file *fp, unsigned int ch36x_cmd, unsigned long ch36x_arg) 1236 | { 1237 | int retval = 0; 1238 | struct list_head *pos; 1239 | struct list_head *pos_tmp; 1240 | struct ch36x_dev *ch36x_dev; 1241 | unsigned int minor = iminor(fp->f_path.dentry->d_inode); 1242 | 1243 | list_for_each_safe(pos, pos_tmp, &g_private_head) { 1244 | ch36x_dev = list_entry(pos, struct ch36x_dev, ch36x_dev_list); 1245 | if (minor == MINOR(ch36x_dev->ch36x_dev)) { 1246 | break; 1247 | } 1248 | } 1249 | if (pos == &g_private_head) { 1250 | pr_err("%s Can't find minor:%d line:%d", __func__, minor, __LINE__); 1251 | return -ENODEV; 1252 | } 1253 | 1254 | mutex_lock(&ch36x_dev->io_mutex); 1255 | retval = ch36x_fops_ioctl_do(ch36x_dev, ch36x_cmd, ch36x_arg); 1256 | mutex_unlock(&ch36x_dev->io_mutex); 1257 | 1258 | return retval; 1259 | } 1260 | 1261 | static int ch36x_fops_fasync(int fd, struct file *fp, int on) 1262 | { 1263 | struct list_head *pos; 1264 | struct list_head *pos_tmp; 1265 | struct ch36x_dev *ch36x_dev; 1266 | unsigned int minor = iminor(fp->f_path.dentry->d_inode); 1267 | 1268 | list_for_each_safe(pos, pos_tmp, &g_private_head) { 1269 | ch36x_dev = list_entry(pos, struct ch36x_dev, ch36x_dev_list); 1270 | if (minor == MINOR(ch36x_dev->ch36x_dev)) { 1271 | break; 1272 | } 1273 | } 1274 | if (pos == &g_private_head) { 1275 | pr_err("Fun:%s Can't find minor:0x%x line:%d", __FUNCTION__, minor, __LINE__); 1276 | return -ENODEV; 1277 | } 1278 | 1279 | return fasync_helper(fd, fp, on, &ch36x_dev->fasync); 1280 | } 1281 | 1282 | static const struct file_operations ch36x_fops = { 1283 | .owner = THIS_MODULE, 1284 | .open = ch36x_fops_open, 1285 | .release = ch36x_fops_release, 1286 | .read = ch36x_fops_read, 1287 | .write = ch36x_fops_write, 1288 | .unlocked_ioctl = ch36x_fops_ioctl, 1289 | .fasync = ch36x_fops_fasync, 1290 | }; 1291 | 1292 | static void ch36x_dump_regs(struct ch36x_dev *ch36x_dev) 1293 | { 1294 | u8 obyte; 1295 | u8 offset; 1296 | u8 configend; 1297 | u8 iostart; 1298 | u8 ioend; 1299 | 1300 | pr_debug("---------- g_dev_count: %d ----------\n", g_dev_count); 1301 | 1302 | pr_debug("\n---------- pci/pcie config space ----------\n"); 1303 | if (ch36x_dev->chiptype == CHIP_CH365) { 1304 | configend = 0x42; 1305 | iostart = 0xf0; 1306 | ioend = 0xfc; 1307 | } else { 1308 | configend = 0x40; 1309 | iostart = 0xe8; 1310 | ioend = 0xfe; 1311 | } 1312 | for (offset = 0; offset <= configend; offset++) { 1313 | pci_read_config_byte(ch36x_dev->ch36x_pdev, offset, &obyte); 1314 | pr_debug("\toffset:0x%2x, val:0x%2x\n", offset, obyte); 1315 | } 1316 | 1317 | pr_debug("\n---------- pci/pcie io space ----------\n"); 1318 | for (offset = iostart; offset <= ioend; offset++) { 1319 | obyte = inb(ch36x_dev->ioaddr + offset); 1320 | pr_debug("\toffset:0x%2x, val:0x%2x\n", offset, obyte); 1321 | } 1322 | 1323 | return; 1324 | } 1325 | 1326 | static void ch36x_unmap_device(struct pci_dev *pdev, struct ch36x_dev *ch36x_dev) 1327 | { 1328 | pci_iounmap(pdev, ch36x_dev->memaddr); 1329 | } 1330 | 1331 | static int ch36x_map_device(struct pci_dev *pdev, struct ch36x_dev *ch36x_dev) 1332 | { 1333 | int ret = -ENOMEM; 1334 | 1335 | ch36x_dev->iolen = pci_resource_len(pdev, 0); 1336 | ch36x_dev->memlen = pci_resource_len(pdev, 1); 1337 | /* map the memory mapped i/o registers */ 1338 | ch36x_dev->ioaddr = pci_resource_start(pdev, 0); 1339 | if (!ch36x_dev->ioaddr) { 1340 | dev_err(&pdev->dev, "Error mapping io\n"); 1341 | goto out; 1342 | } 1343 | ch36x_dev->memaddr = pci_iomap(pdev, 1, ch36x_dev->memlen); 1344 | if (ch36x_dev->memaddr == NULL) { 1345 | dev_err(&pdev->dev, "Error mapping mem\n"); 1346 | goto out; 1347 | } 1348 | ch36x_dev->irq = pdev->irq; 1349 | dev_info(&pdev->dev, "ch36x map succeed.\n"); 1350 | dev_vdbg(&pdev->dev, "***********I/O Port**********\n"); 1351 | dev_vdbg(&pdev->dev, "phy addr: 0x%lx\n", (unsigned long)pci_resource_start(pdev, 0)); 1352 | dev_vdbg(&pdev->dev, "io len: %ld\n", ch36x_dev->iolen); 1353 | dev_vdbg(&pdev->dev, "***********I/O Memory**********\n"); 1354 | dev_vdbg(&pdev->dev, "phy addr: 0x%lx\n", (unsigned long)pci_resource_start(pdev, 1)); 1355 | dev_vdbg(&pdev->dev, "mapped addr: 0x%lx\n", (unsigned long)ch36x_dev->memaddr); 1356 | dev_vdbg(&pdev->dev, "mem len: %ld\n", ch36x_dev->memlen); 1357 | dev_info(&pdev->dev, "irq number is: %d", ch36x_dev->irq); 1358 | 1359 | return 0; 1360 | 1361 | out: 1362 | return ret; 1363 | } 1364 | 1365 | static int ch36x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 1366 | { 1367 | int retval = -ENOMEM; 1368 | struct ch36x_dev *ch36x_dev = NULL; 1369 | struct device *dev; 1370 | 1371 | dev_info(&pdev->dev, "%s\n", __func__); 1372 | ch36x_dev = kzalloc(sizeof(*ch36x_dev), GFP_KERNEL); 1373 | if (!ch36x_dev) 1374 | goto out; 1375 | 1376 | ch36x_dev->ch36x_pdev = pdev; 1377 | if (pdev->device == CH365_DID) 1378 | ch36x_dev->chiptype = CHIP_CH365; 1379 | else if ((pdev->device == CH367_DID_SID_HIGH) || (pdev->device == CH367_DID_SID_LOW)) 1380 | ch36x_dev->chiptype = CHIP_CH367; 1381 | else if (pdev->device == CH368_DID) 1382 | ch36x_dev->chiptype = CHIP_CH368; 1383 | 1384 | retval = pci_enable_device(pdev); 1385 | if (retval) 1386 | goto free; 1387 | 1388 | pci_set_master(pdev); 1389 | 1390 | retval = pci_request_regions(pdev, CH36X_DRV_NAME); 1391 | if (retval) 1392 | goto disable; 1393 | 1394 | mutex_init(&ch36x_dev->io_mutex); 1395 | 1396 | retval = ch36x_map_device(pdev, ch36x_dev); 1397 | if (retval) 1398 | goto free_regions; 1399 | 1400 | pci_set_drvdata(pdev, ch36x_dev); 1401 | sprintf(ch36x_dev->dev_file_name, "%s%c", CH36X_DRV_NAME, '0' + g_dev_count); 1402 | retval = request_irq(ch36x_dev->irq, ch36x_isr, IRQF_SHARED, ch36x_dev->dev_file_name, (void *)ch36x_dev); 1403 | if (retval) { 1404 | dev_err(&pdev->dev, "Could not request irq.\n"); 1405 | goto unmap; 1406 | } 1407 | 1408 | ch36x_dump_regs(ch36x_dev); 1409 | 1410 | cdev_init(&ch36x_dev->cdev, &ch36x_fops); 1411 | ch36x_dev->cdev.owner = THIS_MODULE; 1412 | ch36x_dev->ch36x_dev = MKDEV(ch36x_major, g_dev_count); 1413 | retval = cdev_add(&ch36x_dev->cdev, ch36x_dev->ch36x_dev, 1); 1414 | if (retval) { 1415 | dev_err(&pdev->dev, "Could not add cdev\n"); 1416 | goto remove_isr; 1417 | } 1418 | 1419 | dev = device_create(ch36x_class, &pdev->dev, ch36x_dev->ch36x_dev, NULL, "%s", ch36x_dev->dev_file_name); 1420 | if (IS_ERR(dev)) 1421 | dev_err(&pdev->dev, "Could not create device node.\n"); 1422 | 1423 | list_add_tail(&(ch36x_dev->ch36x_dev_list), &g_private_head); 1424 | g_dev_count++; 1425 | 1426 | dev_info(&pdev->dev, "%s ch36x_pci_probe function finshed.", __func__); 1427 | 1428 | return 0; 1429 | 1430 | remove_isr: 1431 | free_irq(pdev->irq, ch36x_dev); 1432 | unmap: 1433 | ch36x_unmap_device(pdev, ch36x_dev); 1434 | free_regions: 1435 | pci_release_regions(pdev); 1436 | disable: 1437 | pci_disable_device(pdev); 1438 | free: 1439 | kfree(ch36x_dev); 1440 | out: 1441 | return retval; 1442 | } 1443 | 1444 | static void ch36x_pci_remove(struct pci_dev *pdev) 1445 | { 1446 | struct ch36x_dev *ch36x_dev = pci_get_drvdata(pdev); 1447 | 1448 | if (!ch36x_dev) 1449 | return; 1450 | 1451 | dev_info(&pdev->dev, "%s", __func__); 1452 | device_destroy(ch36x_class, ch36x_dev->ch36x_dev); 1453 | cdev_del(&ch36x_dev->cdev); 1454 | free_irq(pdev->irq, ch36x_dev); 1455 | ch36x_unmap_device(pdev, ch36x_dev); 1456 | pci_release_regions(pdev); 1457 | list_del(&(ch36x_dev->ch36x_dev_list)); 1458 | kfree(ch36x_dev); 1459 | } 1460 | 1461 | static struct pci_device_id ch36x_id_table[] = { 1462 | { PCI_DEVICE(CH365_VID, CH365_DID) }, 1463 | { PCI_DEVICE_SUB(CH367_VID, CH367_DID_SID_HIGH, CH367_SUB_VID, CH367_SUB_DID_SID_HIGH) }, 1464 | { PCI_DEVICE_SUB(CH367_VID, CH367_DID_SID_LOW, CH367_SUB_VID, CH367_SUB_DID_SID_LOW) }, 1465 | { PCI_DEVICE_SUB(CH368_VID, CH368_DID, CH368_SUB_VID, CH368_SUB_DID) }, 1466 | {} 1467 | }; 1468 | MODULE_DEVICE_TABLE(pci, ch36x_id_table); 1469 | 1470 | static struct pci_driver ch36x_pci_driver = { 1471 | .name = CH36X_DRV_NAME, 1472 | .id_table = ch36x_id_table, 1473 | .probe = ch36x_pci_probe, 1474 | .remove = ch36x_pci_remove, 1475 | }; 1476 | 1477 | static int __init ch36x_init(void) 1478 | { 1479 | int error; 1480 | dev_t dev; 1481 | 1482 | printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); 1483 | printk(KERN_INFO KBUILD_MODNAME ": " VERSION_DESC "\n"); 1484 | INIT_LIST_HEAD(&g_private_head); 1485 | ch36x_class = class_create(THIS_MODULE, "ch36x_class"); 1486 | if (IS_ERR(ch36x_class)) { 1487 | error = PTR_ERR(ch36x_class); 1488 | goto out; 1489 | } 1490 | 1491 | error = alloc_chrdev_region(&dev, 0, CH36X_MAX_NUM, CH36X_DRV_NAME); 1492 | if (error) 1493 | goto class_destroy; 1494 | 1495 | ch36x_major = MAJOR(dev); 1496 | 1497 | error = pci_register_driver(&ch36x_pci_driver); 1498 | if (error) 1499 | goto chr_remove; 1500 | 1501 | return 0; 1502 | chr_remove: 1503 | unregister_chrdev_region(dev, CH36X_MAX_NUM); 1504 | class_destroy: 1505 | class_destroy(ch36x_class); 1506 | out: 1507 | return error; 1508 | } 1509 | 1510 | static void __exit ch36x_exit(void) 1511 | { 1512 | printk(KERN_INFO KBUILD_MODNAME ": " 1513 | "ch36x driver exit.\n"); 1514 | g_dev_count = 0; 1515 | pci_unregister_driver(&ch36x_pci_driver); 1516 | unregister_chrdev_region(MKDEV(ch36x_major, 0), CH36X_MAX_NUM); 1517 | class_destroy(ch36x_class); 1518 | } 1519 | 1520 | MODULE_AUTHOR(DRIVER_AUTHOR); 1521 | MODULE_DESCRIPTION(DRIVER_DESC); 1522 | MODULE_LICENSE("GPL v2"); 1523 | 1524 | module_init(ch36x_init); 1525 | module_exit(ch36x_exit); 1526 | -------------------------------------------------------------------------------- /lib/ch36x_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ch365/ch367/ch368 PCI/PCIE application library 3 | * 4 | * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd. 5 | * Web: http://wch.cn 6 | * Author: WCH 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * Cross-compile with cross-gcc -I /path/to/cross-kernel/include 14 | * 15 | * Update Log: 16 | * V1.0 - initial version 17 | * V1.1 - modify APIs related to interrupt 18 | * V1.2 - add APIs related to SPI transfer 19 | * V1.3 - fix bugs of memory block read/write 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "ch36x_lib.h" 35 | 36 | static const char *device = "/dev/ch36xpci0"; 37 | 38 | /** 39 | * ch36x_open - open ch36x device 40 | * @devname: the device name to open 41 | * 42 | * The function return the new file descriptor, or -1 if an error occurred 43 | */ 44 | int ch36x_open(const char *devname) 45 | { 46 | int fd; 47 | 48 | fd = open(devname, O_RDWR); 49 | if (fd > 0) { 50 | fcntl(fd, F_SETOWN, getpid()); 51 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC); 52 | } 53 | 54 | return fd; 55 | } 56 | 57 | /** 58 | * ch36x_close - close ch36x device 59 | * @fd: the device handle 60 | * 61 | * The function return 0 if success, others if fail. 62 | */ 63 | int ch36x_close(int fd) 64 | { 65 | return close(fd); 66 | } 67 | 68 | /** 69 | * ch36x_get_chiptype - get chip model 70 | * @fd: file descriptor of ch36x device 71 | * @chiptype: pointer to chiptype 72 | * 73 | * The function return 0 if success, others if fail. 74 | */ 75 | int ch36x_get_chiptype(int fd, enum CHIP_TYPE *chiptype) 76 | { 77 | return ioctl(fd, CH36x_GET_CHIPTYPE, (unsigned long)chiptype); 78 | } 79 | 80 | /** 81 | * ch36x_get_version - get driver version 82 | * @fd: file descriptor of ch36x device 83 | * @version: pointer to version string 84 | * 85 | * The function return 0 if success, others if fail. 86 | */ 87 | int ch36x_get_version(int fd, char *version) 88 | { 89 | return ioctl(fd, CH36x_GET_VERSION, (unsigned long)version); 90 | } 91 | 92 | /** 93 | * ch36x_get_irq - get irq number 94 | * @fd: file descriptor of ch36x device 95 | * @irq: pointer to irq number 96 | * 97 | * The function return 0 if success, others if fail. 98 | */ 99 | int ch36x_get_irq(int fd, int *irq) 100 | { 101 | return ioctl(fd, CH36x_GET_IRQ, (unsigned long)irq); 102 | } 103 | 104 | /** 105 | * ch36x_get_ioaddr - get io base address of ch36x 106 | * @fd: file descriptor of ch36x device 107 | * @ioaddr: pointer to io base address 108 | * 109 | * The function return 0 if success, others if fail. 110 | */ 111 | int ch36x_get_ioaddr(int fd, void *ioaddr) 112 | { 113 | return ioctl(fd, CH36x_GET_IO_BASE_ADDR, (unsigned long)ioaddr); 114 | } 115 | 116 | /** 117 | * ch36x_get_memaddr - get io memory address of ch36x 118 | * @fd: file descriptor of ch36x device 119 | * @memaddr: pointer to memory base address 120 | * 121 | * The function return 0 if success, others if fail. 122 | */ 123 | 124 | int ch36x_get_memaddr(int fd, void *memaddr) 125 | { 126 | return ioctl(fd, CH36x_GET_MEM_BASE_ADDR, (unsigned long)memaddr); 127 | } 128 | 129 | /** 130 | * ch36x_read_config_byte - read one byte from config space 131 | * @fd: file descriptor of ch36x device 132 | * @offset: config space register offset 133 | * @obyte: pointer to read byte 134 | * 135 | * The function return 0 if success, others if fail. 136 | */ 137 | int ch36x_read_config_byte(int fd, uint8_t offset, uint8_t *obyte) 138 | { 139 | struct ch36x_read_config_t { 140 | uint8_t offset; 141 | uint8_t obyte; 142 | } __attribute__((packed)); 143 | 144 | struct ch36x_read_config_t ch36x_read_config; 145 | int ret; 146 | 147 | ch36x_read_config.offset = offset; 148 | 149 | ret = ioctl(fd, CH36x_READ_CONFIG_BYTE, (unsigned long)&ch36x_read_config); 150 | if (ret < 0) { 151 | goto exit; 152 | } 153 | *obyte = ch36x_read_config.obyte; 154 | exit: 155 | return ret; 156 | } 157 | 158 | /** 159 | * ch36x_read_config_word - read one word from config space 160 | * @fd: file descriptor of ch36x device 161 | * @offset: config space register offset 162 | * @oword: pointer to read word 163 | * 164 | * The function return 0 if success, others if fail. 165 | */ 166 | int ch36x_read_config_word(int fd, uint8_t offset, uint16_t *oword) 167 | { 168 | struct ch36x_read_config_t { 169 | uint8_t offset; 170 | uint16_t oword; 171 | } __attribute__((packed)); 172 | 173 | struct ch36x_read_config_t ch36x_read_config; 174 | int ret; 175 | 176 | ch36x_read_config.offset = offset; 177 | 178 | ret = ioctl(fd, CH36x_READ_CONFIG_WORD, (unsigned long)&ch36x_read_config); 179 | if (ret < 0) { 180 | goto exit; 181 | } 182 | *oword = ch36x_read_config.oword; 183 | exit: 184 | return ret; 185 | } 186 | 187 | /** 188 | * ch36x_read_config_dword - read one dword from config space 189 | * @fd: file descriptor of ch36x device 190 | * @offset: config space register offset 191 | * @oword: pointer to read dword 192 | * 193 | * The function return 0 if success, others if fail. 194 | */ 195 | int ch36x_read_config_dword(int fd, uint8_t offset, uint32_t *odword) 196 | { 197 | struct ch36x_read_config_t { 198 | uint8_t offset; 199 | uint32_t odword; 200 | } __attribute__((packed)); 201 | 202 | struct ch36x_read_config_t ch36x_read_config; 203 | int ret; 204 | 205 | ch36x_read_config.offset = offset; 206 | 207 | ret = ioctl(fd, CH36x_READ_CONFIG_DWORD, (unsigned long)&ch36x_read_config); 208 | if (ret < 0) { 209 | goto exit; 210 | } 211 | *odword = ch36x_read_config.odword; 212 | exit: 213 | return ret; 214 | } 215 | 216 | /** 217 | * ch36x_write_config_byte - write one byte to config space 218 | * @fd: file descriptor of ch36x device 219 | * @offset: config space register offset 220 | * @ibyte: byte to write 221 | * 222 | * The function return 0 if success, others if fail. 223 | */ 224 | int ch36x_write_config_byte(int fd, uint8_t offset, uint8_t ibyte) 225 | { 226 | struct ch36x_write_config_t { 227 | uint8_t offset; 228 | uint8_t ibyte; 229 | } __attribute__((packed)); 230 | 231 | struct ch36x_write_config_t ch36x_write_config; 232 | 233 | ch36x_write_config.offset = offset; 234 | ch36x_write_config.ibyte = ibyte; 235 | 236 | return ioctl(fd, CH36x_WRITE_CONFIG_BYTE, (unsigned long)&ch36x_write_config); 237 | } 238 | 239 | /** 240 | * ch36x_write_config_word - write one word to config space 241 | * @fd: file descriptor of ch36x device 242 | * @offset: config space register offset 243 | * @iword: word to write 244 | * 245 | * The function return 0 if success, others if fail. 246 | */ 247 | int ch36x_write_config_word(int fd, uint8_t offset, uint16_t iword) 248 | { 249 | struct ch36x_write_config_t { 250 | uint8_t offset; 251 | uint16_t iword; 252 | } __attribute__((packed)); 253 | 254 | struct ch36x_write_config_t ch36x_write_config; 255 | 256 | ch36x_write_config.offset = offset; 257 | ch36x_write_config.iword = iword; 258 | 259 | return ioctl(fd, CH36x_WRITE_CONFIG_WORD, (unsigned long)&ch36x_write_config); 260 | } 261 | 262 | /** 263 | * ch36x_write_config_dword - write one dword to config space 264 | * @fd: file descriptor of ch36x device 265 | * @offset: config space register offset 266 | * @dword: dword to write 267 | * 268 | * The function return 0 if success, others if fail. 269 | */ 270 | int ch36x_write_config_dword(int fd, uint8_t offset, uint32_t idword) 271 | { 272 | struct ch36x_write_config_t { 273 | uint8_t offset; 274 | uint32_t idword; 275 | } __attribute__((packed)); 276 | 277 | struct ch36x_write_config_t ch36x_write_config; 278 | 279 | ch36x_write_config.offset = offset; 280 | ch36x_write_config.idword = idword; 281 | 282 | return ioctl(fd, CH36x_WRITE_CONFIG_DWORD, (unsigned long)&ch36x_write_config); 283 | } 284 | 285 | /** 286 | * ch36x_read_io_byte - read one byte from io space 287 | * @fd: file descriptor of ch36x device 288 | * @offset: io space register offset 289 | * @obyte: pointer to read byte 290 | * 291 | * The function return 0 if success, others if fail. 292 | */ 293 | int ch36x_read_io_byte(int fd, uint8_t offset, uint8_t *obyte) 294 | { 295 | struct ch36x_read_io_t { 296 | uint8_t offset; 297 | uint8_t obyte; 298 | } __attribute__((packed)); 299 | 300 | struct ch36x_read_io_t ch36x_read_io; 301 | int ret; 302 | 303 | ch36x_read_io.offset = offset; 304 | 305 | ret = ioctl(fd, CH36x_READ_IO_BYTE, (unsigned long)&ch36x_read_io); 306 | if (ret < 0) { 307 | goto exit; 308 | } 309 | *obyte = ch36x_read_io.obyte; 310 | exit: 311 | return ret; 312 | } 313 | 314 | /** 315 | * ch36x_read_io_word - read one byte from io word 316 | * @fd: file descriptor of ch36x device 317 | * @offset: io space register offset 318 | * @oword: pointer to read word 319 | * 320 | * The function return 0 if success, others if fail. 321 | */ 322 | int ch36x_read_io_word(int fd, uint8_t offset, uint16_t *oword) 323 | { 324 | struct ch36x_read_io_t { 325 | uint8_t offset; 326 | uint16_t oword; 327 | } __attribute__((packed)); 328 | 329 | struct ch36x_read_io_t ch36x_read_io; 330 | int ret; 331 | 332 | ch36x_read_io.offset = offset; 333 | 334 | ret = ioctl(fd, CH36x_READ_IO_WORD, (unsigned long)&ch36x_read_io); 335 | if (ret < 0) { 336 | goto exit; 337 | } 338 | *oword = ch36x_read_io.oword; 339 | exit: 340 | return ret; 341 | } 342 | 343 | /** 344 | * ch36x_read_io_dword - read one dword from io space 345 | * @fd: file descriptor of ch36x device 346 | * @offset: io space register offset 347 | * @odword: pointer to read dword 348 | * 349 | * The function return 0 if success, others if fail. 350 | */ 351 | int ch36x_read_io_dword(int fd, uint8_t offset, uint32_t *odword) 352 | { 353 | struct ch36x_read_io_t { 354 | uint8_t offset; 355 | uint32_t odword; 356 | } __attribute__((packed)); 357 | 358 | struct ch36x_read_io_t ch36x_read_io; 359 | int ret; 360 | 361 | ch36x_read_io.offset = offset; 362 | 363 | ret = ioctl(fd, CH36x_READ_IO_DWORD, (unsigned long)&ch36x_read_io); 364 | if (ret < 0) { 365 | goto exit; 366 | } 367 | *odword = ch36x_read_io.odword; 368 | exit: 369 | return ret; 370 | } 371 | 372 | /** 373 | * ch36x_write_io_byte - write one byte to io space 374 | * @fd: file descriptor of ch36x device 375 | * @offset: io space register offset 376 | * @ibyte: byte to write 377 | * 378 | * The function return 0 if success, others if fail. 379 | */ 380 | int ch36x_write_io_byte(int fd, uint8_t offset, uint8_t ibyte) 381 | { 382 | struct ch36x_write_io_t { 383 | uint8_t offset; 384 | uint8_t ibyte; 385 | } __attribute__((packed)); 386 | 387 | struct ch36x_write_io_t ch36x_write_io; 388 | 389 | ch36x_write_io.offset = offset; 390 | ch36x_write_io.ibyte = ibyte; 391 | 392 | return ioctl(fd, CH36x_WRITE_IO_BYTE, (unsigned long)&ch36x_write_io); 393 | } 394 | 395 | /** 396 | * ch36x_write_io_word - write one word to io space 397 | * @fd: file descriptor of ch36x device 398 | * @offset: io space register offset 399 | * @iword: word to write 400 | * 401 | * The function return 0 if success, others if fail. 402 | */ 403 | int ch36x_write_io_word(int fd, uint8_t offset, uint16_t iword) 404 | { 405 | struct ch36x_write_io_t { 406 | uint8_t offset; 407 | uint16_t iword; 408 | } __attribute__((packed)); 409 | 410 | struct ch36x_write_io_t ch36x_write_io; 411 | 412 | ch36x_write_io.offset = offset; 413 | ch36x_write_io.iword = iword; 414 | 415 | return ioctl(fd, CH36x_WRITE_IO_WORD, (unsigned long)&ch36x_write_io); 416 | } 417 | 418 | /** 419 | * ch36x_write_io_dword - write one dword to io space 420 | * @fd: file descriptor of ch36x device 421 | * @offset: io space register offset 422 | * @idword: dword to write 423 | * 424 | * The function return 0 if success, others if fail. 425 | */ 426 | int ch36x_write_io_dword(int fd, uint8_t offset, uint32_t idword) 427 | { 428 | struct ch36x_write_io_t { 429 | uint8_t offset; 430 | uint32_t idword; 431 | } __attribute__((packed)); 432 | 433 | struct ch36x_write_io_t ch36x_write_io; 434 | 435 | ch36x_write_io.offset = offset; 436 | ch36x_write_io.idword = idword; 437 | 438 | return ioctl(fd, CH36x_WRITE_IO_DWORD, (unsigned long)&ch36x_write_io); 439 | } 440 | 441 | /** 442 | * ch36x_read_mem_byte - read one byte from memory space 443 | * @fd: file descriptor of ch36x device 444 | * @offset: memory space address offset 445 | * @obyte: pointer to read byte 446 | * 447 | * The function return 0 if success, others if fail. 448 | */ 449 | int ch36x_read_mem_byte(int fd, uint16_t offset, uint8_t *obyte) 450 | { 451 | struct ch36x_read_mem_t { 452 | uint16_t offset; 453 | uint8_t obyte; 454 | } __attribute__((packed)); 455 | 456 | struct ch36x_read_mem_t ch36x_read_mem; 457 | int ret; 458 | 459 | ch36x_read_mem.offset = offset; 460 | 461 | ret = ioctl(fd, CH36x_READ_MEM_BYTE, (unsigned long)&ch36x_read_mem); 462 | if (ret < 0) { 463 | goto exit; 464 | } 465 | *obyte = ch36x_read_mem.obyte; 466 | exit: 467 | return ret; 468 | } 469 | 470 | /** 471 | * ch36x_read_mem_word - read one word from memory space 472 | * @fd: file descriptor of ch36x device 473 | * @offset: memory space address offset 474 | * @oword: pointer to read word 475 | * 476 | * The function return 0 if success, others if fail. 477 | */ 478 | int ch36x_read_mem_word(int fd, uint16_t offset, uint16_t *oword) 479 | { 480 | struct ch36x_read_mem_t { 481 | uint16_t offset; 482 | uint16_t oword; 483 | } __attribute__((packed)); 484 | 485 | struct ch36x_read_mem_t ch36x_read_mem; 486 | int ret; 487 | 488 | ch36x_read_mem.offset = offset; 489 | 490 | ret = ioctl(fd, CH36x_READ_MEM_WORD, (unsigned long)&ch36x_read_mem); 491 | if (ret < 0) { 492 | goto exit; 493 | } 494 | *oword = ch36x_read_mem.oword; 495 | exit: 496 | return ret; 497 | } 498 | 499 | /** 500 | * ch36x_read_mem_dword - read one dword from memory space 501 | * @fd: file descriptor of ch36x device 502 | * @offset: memory space address offset 503 | * @odword: pointer to read dword 504 | * 505 | * The function return 0 if success, others if fail. 506 | */ 507 | int ch36x_read_mem_dword(int fd, uint16_t offset, uint32_t *odword) 508 | { 509 | struct ch36x_read_mem_t { 510 | uint16_t offset; 511 | uint32_t odword; 512 | } __attribute__((packed)); 513 | 514 | struct ch36x_read_mem_t ch36x_read_mem; 515 | int ret; 516 | 517 | ch36x_read_mem.offset = offset; 518 | 519 | ret = ioctl(fd, CH36x_READ_MEM_DWORD, (unsigned long)&ch36x_read_mem); 520 | if (ret < 0) { 521 | goto exit; 522 | } 523 | *odword = ch36x_read_mem.odword; 524 | exit: 525 | return ret; 526 | } 527 | 528 | /** 529 | * ch36x_write_mem_byte - write one byte to mem space 530 | * @fd: file descriptor of ch36x device 531 | * @offset: memory space address offset 532 | * @ibyte: byte to write 533 | * 534 | * The function return 0 if success, others if fail. 535 | */ 536 | int ch36x_write_mem_byte(int fd, uint16_t offset, uint8_t ibyte) 537 | { 538 | struct ch36x_write_mem_t { 539 | uint16_t offset; 540 | uint8_t ibyte; 541 | } __attribute__((packed)); 542 | 543 | struct ch36x_write_mem_t ch36x_write_mem; 544 | 545 | ch36x_write_mem.offset = offset; 546 | ch36x_write_mem.ibyte = ibyte; 547 | 548 | return ioctl(fd, CH36x_WRITE_MEM_BYTE, (unsigned long)&ch36x_write_mem); 549 | } 550 | 551 | /** 552 | * ch36x_write_mem_word - write one word to mem space 553 | * @fd: file descriptor of ch36x device 554 | * @offset: memory space address offset 555 | * @iword: word to write 556 | * 557 | * The function return 0 if success, others if fail. 558 | */ 559 | int ch36x_write_mem_word(int fd, uint16_t offset, uint16_t iword) 560 | { 561 | struct ch36x_write_mem_t { 562 | uint16_t offset; 563 | uint16_t iword; 564 | } __attribute__((packed)); 565 | 566 | struct ch36x_write_mem_t ch36x_write_mem; 567 | 568 | ch36x_write_mem.offset = offset; 569 | ch36x_write_mem.iword = iword; 570 | 571 | return ioctl(fd, CH36x_WRITE_MEM_WORD, (unsigned long)&ch36x_write_mem); 572 | } 573 | 574 | /** 575 | * ch36x_write_mem_dword - write one dword to mem space 576 | * @fd: file descriptor of ch36x device 577 | * @offset: memory space address offset 578 | * @idword: dword to write 579 | * 580 | * The function return 0 if success, others if fail. 581 | */ 582 | int ch36x_write_mem_dword(int fd, uint16_t offset, uint32_t idword) 583 | { 584 | struct ch36x_write_mem_t { 585 | uint16_t offset; 586 | uint32_t idword; 587 | } __attribute__((packed)); 588 | 589 | struct ch36x_write_mem_t ch36x_write_mem; 590 | 591 | ch36x_write_mem.offset = offset; 592 | ch36x_write_mem.idword = idword; 593 | 594 | return ioctl(fd, CH36x_WRITE_MEM_DWORD, (unsigned long)&ch36x_write_mem); 595 | } 596 | 597 | /** 598 | * ch36x_read_mem_block - read bytes from mem space 599 | * @fd: file descriptor of ch36x device 600 | * @type: SIZE_BYTE: 8-bit read, SIZE_DWORD: 32-bit read 601 | * @offset: memory space address offset 602 | * @obuffer: pointer to read buffer 603 | * @len: length to read 604 | * 605 | * The function return 0 if success, others if fail. 606 | */ 607 | int ch36x_read_mem_block(int fd, uint8_t type, uint16_t offset, uint8_t *obuffer, uint32_t len) 608 | { 609 | struct ch36x_read_mem_t { 610 | uint8_t type; 611 | uint16_t offset; 612 | uint32_t len; 613 | uint8_t data[0]; 614 | } __attribute__((packed)); 615 | 616 | struct ch36x_read_mem_t *ch36x_read_mem; 617 | int ret; 618 | 619 | if ((len <= 0) || (len > sizeof(mCH368_MEM_REG))) 620 | return -1; 621 | 622 | if ((type != SIZE_BYTE) && (type != SIZE_DWORD)) 623 | return -1; 624 | 625 | ch36x_read_mem = malloc(sizeof(struct ch36x_read_mem_t) + len); 626 | 627 | ch36x_read_mem->type = type; 628 | ch36x_read_mem->offset = offset; 629 | ch36x_read_mem->len = len; 630 | 631 | ret = ioctl(fd, CH36x_READ_MEM_BLOCK, (unsigned long)ch36x_read_mem); 632 | if (ret < 0) { 633 | goto exit; 634 | } 635 | 636 | memcpy(obuffer, ch36x_read_mem->data, len); 637 | 638 | exit: 639 | free(ch36x_read_mem); 640 | return ret; 641 | } 642 | 643 | /** 644 | * ch36x_write_mem_block - write bytes to mem space 645 | * @fd: file descriptor of ch36x device 646 | * @type: SIZE_BYTE: 8-bit write, SIZE_DWORD: 32-bit write 647 | * @offset: memory space address offset 648 | * @ibuffer: pointer to write buffer 649 | * @len: length to write 650 | * 651 | * The function return 0 if success, others if fail. 652 | */ 653 | int ch36x_write_mem_block(int fd, uint8_t type, uint16_t offset, uint8_t *ibuffer, uint32_t len) 654 | { 655 | struct ch36x_write_mem_t { 656 | uint8_t type; 657 | uint16_t offset; 658 | uint32_t len; 659 | uint8_t data[0]; 660 | } __attribute__((packed)); 661 | 662 | struct ch36x_write_mem_t *ch36x_write_mem; 663 | int ret; 664 | 665 | if ((len <= 0) || (len > sizeof(mCH368_MEM_REG))) 666 | return -1; 667 | 668 | if ((type != SIZE_BYTE) && (type != SIZE_DWORD)) 669 | return -1; 670 | 671 | ch36x_write_mem = malloc(sizeof(struct ch36x_write_mem_t) + len); 672 | 673 | ch36x_write_mem->type = type; 674 | ch36x_write_mem->offset = offset; 675 | ch36x_write_mem->len = len; 676 | memcpy(ch36x_write_mem->data, ibuffer, len); 677 | 678 | ret = ioctl(fd, CH36x_WRITE_MEM_BLOCK, (unsigned long)ch36x_write_mem); 679 | 680 | free(ch36x_write_mem); 681 | return ret; 682 | } 683 | 684 | /** 685 | * ch36x_enable_isr - enable ch36x interrupt 686 | * @fd: file descriptor of ch36x device 687 | * @mode: interrupt mode 688 | * 689 | * The function return 0 if success, others if fail. 690 | */ 691 | int ch36x_enable_isr(int fd, enum INTMODE mode) 692 | { 693 | return ioctl(fd, CH36x_ENABLE_INT, (unsigned long)&mode); 694 | } 695 | 696 | /** 697 | * ch36x_disable_isr - disable ch36x interrupt 698 | * @fd: file descriptor of ch36x device 699 | * 700 | * The function return 0 if success, others if fail. 701 | */ 702 | int ch36x_disable_isr(int fd) 703 | { 704 | return ioctl(fd, CH36x_DISABLE_INT, NULL); 705 | } 706 | 707 | /** 708 | * ch36x_set_int_routine - set interrupt handler 709 | * @fd: file descriptor of ch36x device 710 | * @isr_handler: handler to call when interrupt occurs 711 | * 712 | */ 713 | void ch36x_set_int_routine(int fd, void *isr_handler) 714 | { 715 | if (isr_handler != NULL) { 716 | signal(SIGIO, isr_handler); 717 | } 718 | } 719 | 720 | /** 721 | * ch36x_set_stream - set spi mode 722 | * @fd: file descriptor of ch36x device 723 | * @mode: bit0 on SPI Freq, 0->31.3MHz, 1->15.6MHz 724 | * bit1 on SPI I/O Pinout, 0->SPI3(SCS/SCL/SDX), 1->SPI4(SCS/SCL/SDX/SDI) 725 | * 726 | * The function return 0 if success, others if fail. 727 | */ 728 | int ch36x_set_stream(int fd, uint8_t mode) 729 | { 730 | return ioctl(fd, CH36x_SET_STREAM, (unsigned long)&mode); 731 | } 732 | 733 | /** 734 | * ch36x_stream_spi - spi transfer 735 | * @fd: file descriptor of ch36x device 736 | * @ibuffer: spi buffer to write 737 | * @len: length to xfer 738 | * @obuffer: pointer to read buffer 739 | * 740 | * The function return 0 if success, others if fail. 741 | */ 742 | int ch36x_stream_spi(int fd, uint8_t *ibuffer, uint32_t ilen, uint8_t *obuffer, uint32_t olen) 743 | { 744 | struct ch36x_stream_spi_t { 745 | uint32_t ilen; 746 | uint32_t olen; 747 | uint8_t ibuffer[mMAX_BUFFER_LENGTH]; 748 | uint8_t obuffer[mMAX_BUFFER_LENGTH]; 749 | } __attribute__((packed)); 750 | 751 | struct ch36x_stream_spi_t ch36x_stream_spi; 752 | int ret; 753 | 754 | if ((ilen < 0) || (ilen > mMAX_BUFFER_LENGTH)) { 755 | return -1; 756 | } 757 | if ((olen < 0) || (olen > mMAX_BUFFER_LENGTH)) { 758 | return -1; 759 | } 760 | ch36x_stream_spi.ilen = ilen; 761 | ch36x_stream_spi.olen = olen; 762 | memcpy(ch36x_stream_spi.ibuffer, ibuffer, ilen); 763 | 764 | ret = ioctl(fd, CH36x_STREAM_SPI, (unsigned long)&ch36x_stream_spi); 765 | if (ret < 0) 766 | goto exit; 767 | 768 | memcpy(obuffer, ch36x_stream_spi.obuffer, olen); 769 | 770 | exit: 771 | return ret; 772 | } 773 | 774 | /** 775 | * ch36x_flash_lock - lock/unlock spi flash 776 | * @fd: file descriptor of ch36x device 777 | * @lock: lock flag, 1 on lock, 0 on unlock 778 | * 779 | * The function return 0 if success, others if fail. 780 | */ 781 | int ch36x_flash_lock(int fd, uint8_t lock) 782 | { 783 | return ioctl(fd, CH36x_FLASH_LOCK, (unsigned long)&lock); 784 | } 785 | 786 | /** 787 | * ch36x_flash_erase - erase spi flash 788 | * @fd: file descriptor of ch36x device 789 | * @addr: spi flash address to erase 790 | * @ilen: length to erase 791 | * 792 | * The function return 0 if success, others if fail. 793 | */ 794 | int ch36x_flash_erase(int fd, uint32_t addr, uint32_t ilen) 795 | { 796 | struct ch36x_stream_spi_t { 797 | uint32_t addr; 798 | uint32_t ilen; 799 | } __attribute__((packed)); 800 | struct ch36x_stream_spi_t ch36x_stream_spi; 801 | 802 | if (ilen < 0) { 803 | return -1; 804 | } 805 | ch36x_stream_spi.addr = addr; 806 | ch36x_stream_spi.ilen = ilen; 807 | 808 | return ioctl(fd, CH36x_FLASH_ERASE, (unsigned long)&ch36x_stream_spi); 809 | } 810 | 811 | /** 812 | * ch36x_flash_read - read spi flash 813 | * @fd: file descriptor of ch36x device 814 | * @addr: spi flash address to read 815 | * @obuffer: pointer to read buffer 816 | * @olen: length to xfer 817 | * 818 | * The function return 0 if success, others if fail. 819 | */ 820 | int ch36x_flash_read(int fd, uint32_t addr, uint8_t *obuffer, uint32_t olen) 821 | { 822 | struct ch36x_stream_spi_t { 823 | uint32_t addr; 824 | uint32_t olen; 825 | uint8_t data[0]; 826 | } __attribute__((packed)); 827 | 828 | struct ch36x_stream_spi_t *ch36x_stream_spi; 829 | int ret; 830 | 831 | if (olen < 0) { 832 | return -1; 833 | } 834 | 835 | ch36x_stream_spi = malloc(sizeof(struct ch36x_stream_spi_t) + olen); 836 | 837 | ch36x_stream_spi->addr = addr; 838 | ch36x_stream_spi->olen = olen; 839 | 840 | ret = ioctl(fd, CH36x_FLASH_READ, (unsigned long)ch36x_stream_spi); 841 | if (ret < 0) { 842 | goto exit; 843 | } 844 | 845 | memcpy(obuffer, ch36x_stream_spi->data, olen); 846 | 847 | exit: 848 | free(ch36x_stream_spi); 849 | return ret; 850 | } 851 | 852 | /** 853 | * ch36x_flash_write - write spi flash 854 | * @fd: file descriptor of ch36x device 855 | * @addr: spi flash address to write 856 | * @ibuffer: pointer to write buffer 857 | * @ilen: length to xfer 858 | * 859 | * The function return 0 if success, others if fail. 860 | */ 861 | int ch36x_flash_write(int fd, uint32_t addr, uint8_t *ibuffer, uint32_t ilen) 862 | { 863 | struct ch36x_stream_spi_t { 864 | uint32_t addr; 865 | uint32_t ilen; 866 | uint8_t data[0]; 867 | } __attribute__((packed)); 868 | 869 | struct ch36x_stream_spi_t *ch36x_stream_spi; 870 | int ret; 871 | 872 | if (ilen < 0) { 873 | return -1; 874 | } 875 | 876 | ch36x_stream_spi = malloc(sizeof(struct ch36x_stream_spi_t) + ilen); 877 | 878 | ch36x_stream_spi->addr = addr; 879 | ch36x_stream_spi->ilen = ilen; 880 | memcpy(ch36x_stream_spi->data, ibuffer, ilen); 881 | 882 | ret = ioctl(fd, CH36x_FLASH_WRITE, (unsigned long)ch36x_stream_spi); 883 | 884 | free(ch36x_stream_spi); 885 | return ret; 886 | } 887 | 888 | int CH36X_SDA_GET(int fd) 889 | { 890 | uint8_t obyte; 891 | 892 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPIR), &obyte); 893 | 894 | return obyte & 0x01; 895 | } 896 | 897 | void CH36X_SDA_SET(int fd) 898 | { 899 | uint8_t obyte; 900 | 901 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), &obyte); 902 | ch36x_write_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), obyte | CH367_GPOR_SET_SDA_BIT); 903 | } 904 | 905 | void CH36X_SDA_CLR(int fd) 906 | { 907 | uint8_t obyte; 908 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), &obyte); 909 | ch36x_write_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), obyte & ~CH367_GPOR_SET_SDA_BIT); 910 | } 911 | 912 | void CH36X_SCL_SET(int fd) 913 | { 914 | uint8_t obyte; 915 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), &obyte); 916 | ch36x_write_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), obyte | CH367_GPOR_SET_SCL_BIT); 917 | } 918 | 919 | void CH36X_SCL_CLR(int fd) 920 | { 921 | uint8_t obyte; 922 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), &obyte); 923 | ch36x_write_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPOR), obyte & ~CH367_GPOR_SET_SCL_BIT); 924 | } 925 | 926 | #define I2C_DELAY1 usleep(5) 927 | #define I2C_DELAY2 usleep(5) 928 | 929 | void I2C_Start(int fd) 930 | { 931 | CH36X_SDA_SET(fd); 932 | CH36X_SCL_SET(fd); 933 | I2C_DELAY1; 934 | CH36X_SDA_CLR(fd); 935 | I2C_DELAY1; 936 | CH36X_SCL_CLR(fd); 937 | } 938 | 939 | void I2C_Stop(int fd) 940 | { 941 | CH36X_SDA_CLR(fd); 942 | CH36X_SCL_CLR(fd); 943 | I2C_DELAY1; 944 | CH36X_SCL_SET(fd); 945 | I2C_DELAY1; 946 | CH36X_SDA_SET(fd); 947 | } 948 | 949 | int I2C_WaitAck(int fd) 950 | { 951 | uint8_t err_times = 0; 952 | uint8_t obyte; 953 | 954 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPIR), &obyte); 955 | I2C_DELAY1; 956 | CH36X_SCL_SET(fd); 957 | I2C_DELAY1; 958 | while (CH36X_SDA_GET(fd)) { 959 | err_times++; 960 | if (err_times > 250) { 961 | I2C_Stop(fd); 962 | return -1; 963 | } 964 | } 965 | CH36X_SCL_CLR(fd); 966 | I2C_DELAY1; 967 | 968 | return 0; 969 | } 970 | 971 | void I2C_SendAck(int fd) 972 | { 973 | CH36X_SCL_CLR(fd); 974 | CH36X_SDA_CLR(fd); 975 | I2C_DELAY1; 976 | CH36X_SCL_SET(fd); 977 | I2C_DELAY1; 978 | CH36X_SCL_CLR(fd); 979 | I2C_DELAY1; 980 | CH36X_SDA_SET(fd); 981 | } 982 | 983 | void I2C_SendNack(int fd) 984 | { 985 | CH36X_SCL_CLR(fd); 986 | CH36X_SDA_SET(fd); 987 | I2C_DELAY1; 988 | CH36X_SCL_SET(fd); 989 | I2C_DELAY1; 990 | CH36X_SCL_CLR(fd); 991 | I2C_DELAY1; 992 | } 993 | 994 | void I2C_SendByte(int fd, uint8_t ibyte) 995 | { 996 | int bit; 997 | 998 | for (bit = 0; bit < 8; bit++) { 999 | CH36X_SCL_CLR(fd); 1000 | if (ibyte & 0x80) 1001 | CH36X_SDA_SET(fd); 1002 | else 1003 | CH36X_SDA_CLR(fd); 1004 | ibyte <<= 1; 1005 | I2C_DELAY1; 1006 | CH36X_SCL_SET(fd); 1007 | I2C_DELAY1; 1008 | } 1009 | CH36X_SCL_CLR(fd); 1010 | } 1011 | 1012 | uint8_t I2C_ReadByte(int fd, uint8_t ack) 1013 | { 1014 | int bit; 1015 | uint8_t ch = 0x00; 1016 | uint8_t obyte; 1017 | 1018 | for (bit = 0; bit < 8; bit++) { 1019 | ch <<= 1; 1020 | CH36X_SCL_CLR(fd); 1021 | I2C_DELAY1; 1022 | CH36X_SCL_SET(fd); 1023 | I2C_DELAY1; 1024 | ch36x_read_io_byte(fd, offsetof(mCH367_IO_REG, mCH367GPIR), &obyte); 1025 | if (obyte & 0x01) 1026 | ch++; 1027 | } 1028 | if (ack) 1029 | I2C_SendAck(fd); 1030 | else 1031 | I2C_SendNack(fd); 1032 | 1033 | return ch; 1034 | } 1035 | 1036 | /** 1037 | * ch36x_i2c_write - write i2c data 1038 | * @fd: file descriptor of ch36x device 1039 | * @addr: i2c device address(low 7 bits specified) 1040 | * @reg: i2c data unit address 1041 | * @ibuffer: data to write 1042 | * @ilen: pointer to length to write 1043 | * 1044 | * The function return 0 if success, others if fail. 1045 | */ 1046 | int ch36x_i2c_write(int fd, uint8_t addr, uint8_t reg, uint8_t *ibuffer, uint32_t ilen) 1047 | { 1048 | int i; 1049 | uint8_t obyte; 1050 | uint8_t ibyte; 1051 | uint8_t bit; 1052 | uint8_t acksta; 1053 | 1054 | /* issue i2c start */ 1055 | I2C_Start(fd); 1056 | 1057 | /* write device address with write flag*/ 1058 | I2C_SendByte(fd, (addr << 1) | 0x00); 1059 | 1060 | /* issue 9th clock to check ack */ 1061 | if (I2C_WaitAck(fd)) { 1062 | I2C_Stop(fd); 1063 | goto out1; 1064 | } 1065 | 1066 | /* write i2c data unit address */ 1067 | I2C_SendByte(fd, reg); 1068 | 1069 | /* issue 9th clock to check ack */ 1070 | if (I2C_WaitAck(fd)) { 1071 | I2C_Stop(fd); 1072 | goto out1; 1073 | } 1074 | 1075 | /* write data */ 1076 | for (i = 0; i < ilen; i++) { 1077 | ibyte = ibuffer[i]; 1078 | 1079 | /* send one byte */ 1080 | I2C_SendByte(fd, ibyte); 1081 | 1082 | /* issue 9th clock to check ack */ 1083 | if (I2C_WaitAck(fd)) { 1084 | I2C_Stop(fd); 1085 | goto out1; 1086 | } 1087 | } 1088 | 1089 | /* issue i2c stop */ 1090 | I2C_Stop(fd); 1091 | 1092 | out: 1093 | return 0; 1094 | out1: 1095 | return -1; 1096 | } 1097 | 1098 | /** 1099 | * ch36x_i2c_read - read i2c data 1100 | * @fd: file descriptor of ch36x device 1101 | * @addr: i2c device address(low 7 bits specified) 1102 | * @reg: i2c data unit address 1103 | * @obuffer: pointer to read data 1104 | * @olen: pointer to length to read 1105 | * 1106 | * The function return 0 if success, others if fail. 1107 | */ 1108 | int ch36x_i2c_read(int fd, uint8_t addr, uint8_t reg, uint8_t *obuffer, uint32_t olen) 1109 | { 1110 | int i; 1111 | uint8_t obyte; 1112 | uint8_t ibyte; 1113 | uint8_t bit; 1114 | uint8_t acksta; 1115 | 1116 | /* issue i2c start */ 1117 | I2C_Start(fd); 1118 | 1119 | /* write device address with write flag*/ 1120 | I2C_SendByte(fd, (addr << 1) | 0x00); 1121 | 1122 | /* issue 9th clock to check ack */ 1123 | if (I2C_WaitAck(fd)) { 1124 | I2C_Stop(fd); 1125 | goto out1; 1126 | } 1127 | 1128 | /* write i2c data unit address */ 1129 | I2C_SendByte(fd, reg); 1130 | 1131 | /* issue 9th clock to check ack */ 1132 | if (I2C_WaitAck(fd)) { 1133 | I2C_Stop(fd); 1134 | goto out1; 1135 | } 1136 | 1137 | /* issue i2c repeat start */ 1138 | I2C_Start(fd); 1139 | 1140 | /* write device address with read flag*/ 1141 | I2C_SendByte(fd, (addr << 1) | 0x01); 1142 | 1143 | /* issue 9th clock to check ack */ 1144 | if (I2C_WaitAck(fd)) { 1145 | I2C_Stop(fd); 1146 | goto out1; 1147 | } 1148 | 1149 | /* read data */ 1150 | for (i = 0; i < olen; i++) { 1151 | /* the last byte has been readed, send nack to device, else send ack */ 1152 | if (i == (olen - 1)) 1153 | *obuffer++ = I2C_ReadByte(fd, 0); 1154 | else 1155 | *obuffer++ = I2C_ReadByte(fd, 1); 1156 | } 1157 | 1158 | /* issue i2c stop */ 1159 | I2C_Stop(fd); 1160 | 1161 | out: 1162 | return 0; 1163 | out1: 1164 | return -1; 1165 | } 1166 | -------------------------------------------------------------------------------- /lib/ch36x_lib.h: -------------------------------------------------------------------------------- 1 | #ifndef _CH36X_LIB_H 2 | #define _CH36X_LIB_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | enum CHIP_TYPE { 9 | CHIP_CH365 = 1, 10 | CHIP_CH367, 11 | CHIP_CH368 12 | }; 13 | 14 | enum INTMODE { 15 | INT_NONE = 0, 16 | INT_LOW, 17 | INT_HIGH, 18 | INT_RISING, 19 | INT_FALLING 20 | }; 21 | 22 | #define BIT(i) (1 << i) 23 | 24 | #define SIZE_BYTE 0x01 25 | #define SIZE_WORD 0x02 26 | #define SIZE_DWORD 0x03 27 | 28 | #define IOCTL_MAGIC 'P' 29 | #define CH36x_GET_IO_BASE_ADDR _IOR(IOCTL_MAGIC, 0x80, uint16_t) 30 | #define CH36x_GET_MEM_BASE_ADDR _IOR(IOCTL_MAGIC, 0x81, uint16_t) 31 | 32 | /* io/mem rw codes */ 33 | #define CH36x_READ_CONFIG_BYTE _IOR(IOCTL_MAGIC, 0x82, uint16_t) 34 | #define CH36x_READ_CONFIG_WORD _IOR(IOCTL_MAGIC, 0x83, uint16_t) 35 | #define CH36x_READ_CONFIG_DWORD _IOR(IOCTL_MAGIC, 0x84, uint16_t) 36 | #define CH36x_WRITE_CONFIG_BYTE _IOW(IOCTL_MAGIC, 0x85, uint16_t) 37 | #define CH36x_WRITE_CONFIG_WORD _IOW(IOCTL_MAGIC, 0x86, uint16_t) 38 | #define CH36x_WRITE_CONFIG_DWORD _IOW(IOCTL_MAGIC, 0x87, uint16_t) 39 | 40 | #define CH36x_READ_IO_BYTE _IOR(IOCTL_MAGIC, 0x88, uint16_t) 41 | #define CH36x_READ_IO_WORD _IOR(IOCTL_MAGIC, 0x89, uint16_t) 42 | #define CH36x_READ_IO_DWORD _IOR(IOCTL_MAGIC, 0x8a, uint16_t) 43 | #define CH36x_WRITE_IO_BYTE _IOW(IOCTL_MAGIC, 0x8b, uint16_t) 44 | #define CH36x_WRITE_IO_WORD _IOW(IOCTL_MAGIC, 0x8c, uint16_t) 45 | #define CH36x_WRITE_IO_DWORD _IOW(IOCTL_MAGIC, 0x8d, uint16_t) 46 | 47 | #define CH36x_READ_MEM_BYTE _IOR(IOCTL_MAGIC, 0x8e, uint16_t) 48 | #define CH36x_READ_MEM_WORD _IOR(IOCTL_MAGIC, 0x8f, uint16_t) 49 | #define CH36x_READ_MEM_DWORD _IOR(IOCTL_MAGIC, 0x90, uint16_t) 50 | #define CH36x_WRITE_MEM_BYTE _IOW(IOCTL_MAGIC, 0x91, uint16_t) 51 | #define CH36x_WRITE_MEM_WORD _IOW(IOCTL_MAGIC, 0x92, uint16_t) 52 | #define CH36x_WRITE_MEM_DWORD _IOW(IOCTL_MAGIC, 0x93, uint16_t) 53 | #define CH36x_READ_MEM_BLOCK _IOR(IOCTL_MAGIC, 0x94, uint16_t) 54 | #define CH36x_WRITE_MEM_BLOCK _IOW(IOCTL_MAGIC, 0x95, uint16_t) 55 | 56 | /* interrupt codes */ 57 | #define CH36x_ENABLE_INT _IOW(IOCTL_MAGIC, 0x96, uint16_t) 58 | #define CH36x_DISABLE_INT _IOW(IOCTL_MAGIC, 0x97, uint16_t) 59 | #define CH36x_GET_IRQ _IOR(IOCTL_MAGIC, 0xa0, uint16_t) 60 | 61 | /* other codes */ 62 | #define CH36x_GET_CHIPTYPE _IOR(IOCTL_MAGIC, 0x98, uint16_t) 63 | #define CH36x_GET_VERSION _IOR(IOCTL_MAGIC, 0x99, uint16_t) 64 | #define CH36x_SET_STREAM _IOW(IOCTL_MAGIC, 0x9a, uint16_t) 65 | #define CH36x_STREAM_SPI _IOWR(IOCTL_MAGIC, 0x9b, uint16_t) 66 | #define CH36x_FLASH_LOCK _IOW(IOCTL_MAGIC, 0x9c, uint16_t) 67 | #define CH36x_FLASH_ERASE _IOW(IOCTL_MAGIC, 0x9d, uint16_t) 68 | #define CH36x_FLASH_READ _IOWR(IOCTL_MAGIC, 0x9e, uint16_t) 69 | #define CH36x_FLASH_WRITE _IOW(IOCTL_MAGIC, 0x9f, uint16_t) 70 | 71 | /* IOCTRL register bits */ 72 | #define CH365_IOCTRL_A15_BIT BIT(0) /* Set A15 */ 73 | #define CH365_IOCTRL_SYS_EX_BIT BIT(1) /* Set SYS_EX */ 74 | #define CH365_IOCTRL_INTA_BIT BIT(2) /* INT Active status */ 75 | 76 | /* MICSR register bits */ 77 | #define CH367_MICSR_GPO_BIT BIT(0) /* Set GPO */ 78 | #define CH367_MICSR_INTA_BIT BIT(2) /* INT Active status */ 79 | #define CH367_MICSR_INTS_BIT BIT(3) /* INT status */ 80 | #define CH367_MICSR_RSTO_BIT BIT(7) /* Set RSTO */ 81 | 82 | /* INTCR register bits */ 83 | #define CH367_INTCR_MSI_ENABLE_BIT BIT(0) /* MSI Enable */ 84 | #define CH367_INTCR_INT_ENABLE_BIT BIT(1) /* Global INT Enable */ 85 | #define CH367_INTCR_INT_POLAR_BIT BIT(2) /* Set INT Polar */ 86 | #define CH367_INTCR_INT_TYPE_BIT BIT(3) /* Set INT Type */ 87 | #define CH367_INTCR_INT_RETRY_BIT BIT(4) /* Set INT Retry */ 88 | 89 | /* GPOR register bits */ 90 | #define CH367_GPOR_SET_SDA_BIT BIT(0) /* Set SDA Value */ 91 | #define CH367_GPOR_SET_SCL_BIT BIT(1) /* Set SCL Value */ 92 | #define CH367_GPOR_SET_SCS_BIT BIT(2) /* Set SCS Value */ 93 | #define CH367_GPOR_ENABLE_WAKE_BIT BIT(5) /* Force Wakeup Support */ 94 | #define CH367_GPOR_SET_SDX_DIR_BIT BIT(6) /* Set SDX Direction */ 95 | #define CH367_GPOR_SET_SDX_BIT BIT(7) /* Set SDX Value */ 96 | 97 | /* SPICR register bits */ 98 | #define CH367_SPICR_SPI_status_BIT BIT(4) /* SPI Transfer Ongoing status */ 99 | #define CH367_SPICR_SPI_FREQ_BIT BIT(5) /* Set SPI Freq: 1->15.6MHz 0->31.3MHz */ 100 | #define CH367_SPICR_SPI_SLT_SDI_BIT BIT(6) /* Set SPI Data In Pin: 1->SDI 0->SDX */ 101 | #define CH367_SPICR_SPI_NEWTRAN_BIT BIT(7) /* Begin New Transfer After Read SPIDR */ 102 | 103 | typedef struct _CH365_IO_REG { // CH365 IO space 104 | uint8_t mCh365IoPort[0xf0]; // 00H-EFH, 240 bytes standard IO bytes 105 | union { 106 | uint16_t mCh365MemAddr; // F0H Memory Interface: A15-A0 address setting register 107 | struct { 108 | uint8_t mCh365MemAddrL; // F0H Memory Interface: A7-A0 address setting register 109 | uint8_t mCh365MemAddrH; // F1H Memory Interface: A15-A8 address setting register 110 | }; 111 | }; 112 | uint8_t mCh365IoResv2; // F2H 113 | uint8_t mCh365MemData; // F3H Memory Interface: Memory data access register 114 | uint8_t mCh365I2cData; // F4H I2C Interface: I2C data access register 115 | uint8_t mCh365I2cCtrl; // F5H I2C Interface: I2C control and status register 116 | uint8_t mCh365I2cAddr; // F6H I2C Interface: I2C address setting register 117 | uint8_t mCh365I2cDev; // F7H I2C Interface: I2C device address and command register 118 | uint8_t mCh365IoCtrl; // F8H Control register, high 5 bits are read-only 119 | uint8_t mCh365IoBuf; // F9H Local data input buffer register 120 | uint8_t mCh365Speed; // FAH Speed control register 121 | uint8_t mCh365IoResv3; // FBH 122 | uint8_t mCh365IoTime; // FCH Hardware loop count register 123 | uint8_t mCh365IoResv4[3]; // FDH 124 | } mCH365_IO_REG, *mPCH365_IO_REG; 125 | 126 | typedef struct _CH365_MEM_REG { // CH365 Memory space 127 | uint8_t mCh365MemPort[0x8000]; // 0000H-7FFFH, 32768 bytes in total 128 | } mCH365_MEM_REG, *mPCH365_MEM_REG; 129 | 130 | typedef struct _CH367_IO_REG { // CH367 IO space 131 | uint8_t mCH367IoPort[0xE8]; // 00H-E7H, 232 bytes standard IO bytes 132 | uint8_t mCH367GPOR; // E8H General output register 133 | uint8_t mCH367GPVR; // E9H General variable register 134 | uint8_t mCH367GPIR; // EAH General input register 135 | uint8_t mCH367IntCtr; // EBH Interrupt control register 136 | union { 137 | uint8_t mCH367IoBuf8; // ECH 8-bit passive parallel interface data buffer 138 | uint32_t mCH367IoBuf32; // ECH 32-bit passive parallel interface data buffer 139 | }; 140 | union { 141 | uint16_t mCH368MemAddr; // F0H Memory Interface: A15-A0 address setting register 142 | struct { 143 | uint8_t mCH368MemAddrL; // F0H Memory Interface: A7-A0 address setting register 144 | union { 145 | uint8_t mCH368MemAddrH; // F1H Memory Interface: A15-A8 address setting register 146 | uint8_t mCH367GPOR2; // F1H General output register 2 147 | }; 148 | } ASR; 149 | }; 150 | uint8_t mCH367IORESV2; // F2H 151 | uint8_t mCH368MemData; // F3H Memory Interface: Memory data access register 152 | union { 153 | uint8_t mCH367Data8Sta; // F4H D7-D0 port status register 154 | uint32_t mCH367SData32Sta; // F4H D31-D0 port status register 155 | }; 156 | uint8_t mCH367Status; // F8H Miscellaneous control and status register 157 | uint8_t mCH367IO_RESV3; // F9H 158 | uint8_t mCH367Speed; // FAH Speed control register 159 | uint8_t mCH367PDataCtrl; // FBH Passive parallel interface control register 160 | uint8_t mCH367IoTime; // FCH Hardware loop count register 161 | uint8_t mCH367SPICtrl; // FDH SPI control register 162 | uint8_t mCH367SPIData; // FEH SPI data register 163 | uint8_t mCH367IO_RESV4; // FFH 164 | } mCH367_IO_REG, *mPCH367_IO_REG; 165 | 166 | typedef struct _CH368_MEM_REG { // CH367 Memory space 167 | uint8_t mCH368MemPort[0x8000]; // 0000H-7FFFH, 32768 bytes in total 168 | } mCH368_MEM_REG, *mPCH368_MEM_REG; 169 | 170 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 171 | #define mMAX_BUFFER_LENGTH MAX(sizeof(mCH367_IO_REG), sizeof(mCH368_MEM_REG)) 172 | 173 | /** 174 | * ch36x_open - open ch36x device 175 | * @devname: the device name to open 176 | * 177 | * The function return the new file descriptor, or -1 if an error occurred 178 | */ 179 | extern int ch36x_open(const char *devname); 180 | /** 181 | * ch36x_close - close ch36x device 182 | * @fd: the device handle 183 | * 184 | * The function return 0 if success, others if fail. 185 | */ 186 | extern int ch36x_close(int fd); 187 | 188 | /** 189 | * ch36x_get_chiptype - get chip model 190 | * @fd: file descriptor of ch36x device 191 | * @chiptype: pointer to chiptype 192 | * 193 | * The function return 0 if success, others if fail. 194 | */ 195 | extern int ch36x_get_chiptype(int fd, enum CHIP_TYPE *chiptype); 196 | 197 | /** 198 | * ch36x_get_version - get driver version 199 | * @fd: file descriptor of ch36x device 200 | * @version: pointer to version string 201 | * 202 | * The function return 0 if success, others if fail. 203 | */ 204 | extern int ch36x_get_version(int fd, char *version); 205 | 206 | /** 207 | * ch36x_get_irq - get irq number 208 | * @fd: file descriptor of ch36x device 209 | * @irq: pointer to irq number 210 | * 211 | * The function return 0 if success, others if fail. 212 | */ 213 | extern int ch36x_get_irq(int fd, int *irq); 214 | 215 | /** 216 | * ch36x_get_ioaddr - get io base address of ch36x 217 | * @fd: file descriptor of ch36x device 218 | * @ioaddr: pointer to io base address 219 | * 220 | * The function return 0 if success, others if fail. 221 | */ 222 | extern int ch36x_get_ioaddr(int fd, void *ioaddr); 223 | 224 | /** 225 | * ch36x_get_memaddr - get io memory address of ch36x 226 | * @fd: file descriptor of ch36x device 227 | * @memaddr: pointer to memory base address 228 | * 229 | * The function return 0 if success, others if fail. 230 | */ 231 | 232 | extern int ch36x_get_memaddr(int fd, void *memaddr); 233 | 234 | /** 235 | * ch36x_read_config_byte - read one byte from config space 236 | * @fd: file descriptor of ch36x device 237 | * @offset: config space register offset 238 | * @obyte: pointer to read byte 239 | * 240 | * The function return 0 if success, others if fail. 241 | */ 242 | extern int ch36x_read_config_byte(int fd, uint8_t offset, uint8_t *obyte); 243 | 244 | /** 245 | * ch36x_read_config_word - read one word from config space 246 | * @fd: file descriptor of ch36x device 247 | * @offset: config space register offset 248 | * @oword: pointer to read word 249 | * 250 | * The function return 0 if success, others if fail. 251 | */ 252 | extern int ch36x_read_config_word(int fd, uint8_t offset, uint16_t *oword); 253 | 254 | /** 255 | * ch36x_read_config_dword - read one dword from config space 256 | * @fd: file descriptor of ch36x device 257 | * @offset: config space register offset 258 | * @oword: pointer to read dword 259 | * 260 | * The function return 0 if success, others if fail. 261 | */ 262 | extern int ch36x_read_config_dword(int fd, uint8_t offset, uint32_t *odword); 263 | 264 | /** 265 | * ch36x_write_config_byte - write one byte to config space 266 | * @fd: file descriptor of ch36x device 267 | * @offset: config space register offset 268 | * @ibyte: byte to write 269 | * 270 | * The function return 0 if success, others if fail. 271 | */ 272 | extern int ch36x_write_config_byte(int fd, uint8_t offset, uint8_t ibyte); 273 | 274 | /** 275 | * ch36x_write_config_word - write one word to config space 276 | * @fd: file descriptor of ch36x device 277 | * @offset: config space register offset 278 | * @iword: word to write 279 | * 280 | * The function return 0 if success, others if fail. 281 | */ 282 | extern int ch36x_write_config_word(int fd, uint8_t offset, uint16_t iword); 283 | 284 | /** 285 | * ch36x_write_config_dword - write one dword to config space 286 | * @fd: file descriptor of ch36x device 287 | * @offset: config space register offset 288 | * @dword: dword to write 289 | * 290 | * The function return 0 if success, others if fail. 291 | */ 292 | extern int ch36x_write_config_dword(int fd, uint8_t offset, uint32_t idword); 293 | 294 | /** 295 | * ch36x_read_io_byte - read one byte from io space 296 | * @fd: file descriptor of ch36x device 297 | * @offset: io space register offset 298 | * @obyte: pointer to read byte 299 | * 300 | * The function return 0 if success, others if fail. 301 | */ 302 | extern int ch36x_read_io_byte(int fd, uint8_t offset, uint8_t *obyte); 303 | 304 | /** 305 | * ch36x_read_io_word - read one byte from io word 306 | * @fd: file descriptor of ch36x device 307 | * @offset: io space register offset 308 | * @oword: pointer to read word 309 | * 310 | * The function return 0 if success, others if fail. 311 | */ 312 | extern int ch36x_read_io_word(int fd, uint8_t offset, uint16_t *oword); 313 | 314 | /** 315 | * ch36x_read_io_dword - read one dword from io space 316 | * @fd: file descriptor of ch36x device 317 | * @offset: io space register offset 318 | * @odword: pointer to read dword 319 | * 320 | * The function return 0 if success, others if fail. 321 | */ 322 | extern int ch36x_read_io_dword(int fd, uint8_t offset, uint32_t *odword); 323 | 324 | /** 325 | * ch36x_write_io_byte - write one byte to io space 326 | * @fd: file descriptor of ch36x device 327 | * @offset: io space register offset 328 | * @ibyte: byte to write 329 | * 330 | * The function return 0 if success, others if fail. 331 | */ 332 | extern int ch36x_write_io_byte(int fd, uint8_t offset, uint8_t ibyte); 333 | 334 | /** 335 | * ch36x_write_io_word - write one word to io space 336 | * @fd: file descriptor of ch36x device 337 | * @offset: io space register offset 338 | * @iword: word to write 339 | * 340 | * The function return 0 if success, others if fail. 341 | */ 342 | extern int ch36x_write_io_word(int fd, uint8_t offset, uint16_t iword); 343 | 344 | /** 345 | * ch36x_write_io_dword - write one dword to io space 346 | * @fd: file descriptor of ch36x device 347 | * @offset: io space register offset 348 | * @idword: dword to write 349 | * 350 | * The function return 0 if success, others if fail. 351 | */ 352 | extern int ch36x_write_io_dword(int fd, uint8_t offset, uint32_t idword); 353 | 354 | /** 355 | * ch36x_read_mem_byte - read one byte from memory space 356 | * @fd: file descriptor of ch36x device 357 | * @offset: memory space address offset 358 | * @obyte: pointer to read byte 359 | * 360 | * The function return 0 if success, others if fail. 361 | */ 362 | extern int ch36x_read_mem_byte(int fd, uint16_t offset, uint8_t *obyte); 363 | 364 | /** 365 | * ch36x_read_mem_word - read one word from memory space 366 | * @fd: file descriptor of ch36x device 367 | * @offset: memory space address offset 368 | * @oword: pointer to read word 369 | * 370 | * The function return 0 if success, others if fail. 371 | */ 372 | extern int ch36x_read_mem_word(int fd, uint16_t offset, uint16_t *oword); 373 | 374 | /** 375 | * ch36x_read_mem_dword - read one dword from memory space 376 | * @fd: file descriptor of ch36x device 377 | * @offset: memory space address offset 378 | * @odword: pointer to read dword 379 | * 380 | * The function return 0 if success, others if fail. 381 | */ 382 | extern int ch36x_read_mem_dword(int fd, uint16_t offset, uint32_t *odword); 383 | 384 | /** 385 | * ch36x_write_mem_byte - write one byte to mem space 386 | * @fd: file descriptor of ch36x device 387 | * @offset: memory space address offset 388 | * @ibyte: byte to write 389 | * 390 | * The function return 0 if success, others if fail. 391 | */ 392 | extern int ch36x_write_mem_byte(int fd, uint16_t offset, uint8_t ibyte); 393 | 394 | /** 395 | * ch36x_write_mem_word - write one word to mem space 396 | * @fd: file descriptor of ch36x device 397 | * @offset: memory space address offset 398 | * @iword: word to write 399 | * 400 | * The function return 0 if success, others if fail. 401 | */ 402 | extern int ch36x_write_mem_word(int fd, uint16_t offset, uint16_t iword); 403 | 404 | /** 405 | * ch36x_write_mem_dword - write one dword to mem space 406 | * @fd: file descriptor of ch36x device 407 | * @offset: memory space address offset 408 | * @idword: dword to write 409 | * 410 | * The function return 0 if success, others if fail. 411 | */ 412 | extern int ch36x_write_mem_dword(int fd, uint16_t offset, uint32_t idword); 413 | 414 | /** 415 | * ch36x_read_mem_block - read bytes from mem space 416 | * @fd: file descriptor of ch36x device 417 | * @type: SIZE_BYTE: 8-bit read, SIZE_DWORD: 32-bit read 418 | * @offset: memory space address offset 419 | * @obuffer: pointer to read buffer 420 | * @len: length to read 421 | * 422 | * The function return 0 if success, others if fail. 423 | */ 424 | extern int ch36x_read_mem_block(int fd, uint8_t type, uint16_t offset, uint8_t *obuffer, uint32_t len); 425 | 426 | /** 427 | * ch36x_write_mem_block - write bytes to mem space 428 | * @fd: file descriptor of ch36x device 429 | * @type: SIZE_BYTE: 8-bit write, SIZE_DWORD: 32-bit write 430 | * @offset: memory space address offset 431 | * @ibuffer: pointer to write buffer 432 | * @len: length to write 433 | * 434 | * The function return 0 if success, others if fail. 435 | */ 436 | extern int ch36x_write_mem_block(int fd, uint8_t type, uint16_t offset, uint8_t *ibuffer, uint32_t len); 437 | 438 | /** 439 | * ch36x_enable_isr - enable ch36x interrupt 440 | * @fd: file descriptor of ch36x device 441 | * @mode: interrupt mode 442 | * 443 | * The function return 0 if success, others if fail. 444 | */ 445 | extern int ch36x_enable_isr(int fd, enum INTMODE mode); 446 | 447 | /** 448 | * ch36x_disable_isr - disable ch36x interrupt 449 | * @fd: file descriptor of ch36x device 450 | * 451 | * The function return 0 if success, others if fail. 452 | */ 453 | extern int ch36x_disable_isr(int fd); 454 | 455 | /** 456 | * ch36x_set_int_routine - set interrupt handler 457 | * @fd: file descriptor of ch36x device 458 | * @isr_handler: handler to call when interrupt occurs 459 | * 460 | */ 461 | extern void ch36x_set_int_routine(int fd, void *isr_handler); 462 | 463 | /** 464 | * ch36x_set_stream - set spi mode 465 | * @fd: file descriptor of ch36x device 466 | * @mode: bit0 on SPI Freq, 0->31.3MHz, 1->15.6MHz 467 | * bit1 on SPI I/O Pinout, 0->SPI3(SCS/SCL/SDX), 1->SPI4(SCS/SCL/SDX/SDI) 468 | * 469 | * The function return 0 if success, others if fail. 470 | */ 471 | extern int ch36x_set_stream(int fd, uint8_t mode); 472 | 473 | /** 474 | * ch36x_stream_spi - spi transfer 475 | * @fd: file descriptor of ch36x device 476 | * @ibuffer: spi buffer to write 477 | * @len: length to xfer 478 | * @obuffer: pointer to read buffer 479 | * 480 | * The function return 0 if success, others if fail. 481 | */ 482 | extern int ch36x_stream_spi(int fd, uint8_t *ibuffer, uint32_t ilen, uint8_t *obuffer, uint32_t olen); 483 | 484 | /** 485 | * ch36x_flash_lock - lock/unlock spi flash 486 | * @fd: file descriptor of ch36x device 487 | * @lock: lock flag, 1 on lock, 0 on unlock 488 | * 489 | * The function return 0 if success, others if fail. 490 | */ 491 | extern int ch36x_flash_lock(int fd, uint8_t lock); 492 | 493 | /** 494 | * ch36x_flash_erase - erase spi flash 495 | * @fd: file descriptor of ch36x device 496 | * @addr: spi flash address to erase 497 | * @ilen: length to erase 498 | * 499 | * The function return 0 if success, others if fail. 500 | */ 501 | extern int ch36x_flash_erase(int fd, uint32_t addr, uint32_t ilen); 502 | 503 | /** 504 | * ch36x_flash_read - read spi flash 505 | * @fd: file descriptor of ch36x device 506 | * @addr: spi flash address to read 507 | * @obuffer: pointer to read buffer 508 | * @olen: length to xfer 509 | * 510 | * The function return 0 if success, others if fail. 511 | */ 512 | extern int ch36x_flash_read(int fd, uint32_t addr, uint8_t *obuffer, uint32_t olen); 513 | 514 | /** 515 | * ch36x_flash_write - write spi flash 516 | * @fd: file descriptor of ch36x device 517 | * @addr: spi flash address to write 518 | * @ibuffer: pointer to write buffer 519 | * @ilen: length to xfer 520 | * 521 | * The function return 0 if success, others if fail. 522 | */ 523 | extern int ch36x_flash_write(int fd, uint32_t addr, uint8_t *ibuffer, uint32_t ilen); 524 | 525 | /** 526 | * ch36x_i2c_write - write i2c data 527 | * @fd: file descriptor of ch36x device 528 | * @addr: i2c device address(low 7 bits specified) 529 | * @reg: i2c data unit address 530 | * @ibuffer: data to write 531 | * @ilen: pointer to length to write 532 | * 533 | * The function return 0 if success, others if fail. 534 | */ 535 | extern int ch36x_i2c_write(int fd, uint8_t addr, uint8_t reg, uint8_t *ibuffer, uint32_t ilen); 536 | 537 | /** 538 | * ch36x_i2c_read - read i2c data 539 | * @fd: file descriptor of ch36x device 540 | * @addr: i2c device address(low 7 bits specified) 541 | * @reg: i2c data unit address 542 | * @obuffer: pointer to read data 543 | * @olen: pointer to length to read 544 | * 545 | * The function return 0 if success, others if fail. 546 | */ 547 | extern int ch36x_i2c_read(int fd, uint8_t addr, uint8_t reg, uint8_t *obuffer, uint32_t olen); 548 | 549 | #endif 550 | --------------------------------------------------------------------------------