spi.c
上传用户:beauty0755
上传日期:2022-02-24
资源大小:7k
文件大小:6k
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/proc_fs.h>
- #include <asm/uaccess.h>
- #include "spi.h"
- #define DEBUG
- #ifdef DEBUG
- #define PRINTK(format,argument...) printk(format,##argument)
- #else
- #define PRINTK(format,argument...)
- #endif
- MODULE_DESCRIPTION("IXP400 GPIO spi driver");
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("ONet Corporation");
- #define MODULE_NAME "spi"
- #define MOD_VERSION "0.1"
- static int sb_gpio_init(void)
- {
- uint32_t gpio;
-
- gpio = SPI_SCK | SPI_SS |SPI_MOSI;
- *IXP4XX_GPIO_GPOER &= ~gpio;
-
- *IXP4XX_GPIO_GPOUTR |= SPI_SCK;
- *IXP4XX_GPIO_GPOUTR |= SPI_SS;
- *IXP4XX_GPIO_GPOUTR |= SPI_MISO;
- *IXP4XX_GPIO_GPOUTR |= SPI_MOSI;
-
- return 0;
- }
- static int sb_gpio(int out, unsigned long gpio,int logic)
- {
- int val = 0;
-
- if(out)
- {
- if(logic)
- *IXP4XX_GPIO_GPOUTR |= gpio;
- else
- *IXP4XX_GPIO_GPOUTR &= ~gpio;
- }else
- {
- val = (*IXP4XX_GPIO_GPINR & gpio)?1:0;
- return val;
- }
-
- return 0;
- }
- static int sb_spi_read(uint8_t * buf, int len)
- {
- int i;
- uint8_t mask, byte;
-
- for (i = 0; i < len; i++) {
- /* Bit bang from MSB to LSB */
- for (mask = 0x80, byte = 0; mask; mask >>= 1) {
- /* Clock low */
- sb_gpio(GPIOOUTPUT, SPI_SCK, 0);
- POLL_DELAY();
- /* Sample */
- if (sb_gpio(GPIOINPUT, SPI_MISO, 0))
- byte |= mask;
- /* Clock high */
- sb_gpio(GPIOOUTPUT, SPI_SCK, 1);
- POLL_DELAY();
- }
- buf[i] = byte;
- }
- return 0;
- }
- static int sb_spi_write(uint8_t *buf, int len)
- {
- int i;
- uint8_t mask;
- for (i = 0; i < len; i++) {
- /* Bit bang from MSB to LSB */
-
- for (mask = 0x80; mask; mask >>= 1) {
- /* Clock low */
- sb_gpio(GPIOOUTPUT, SPI_SCK, 0);
- POLL_DELAY();
- /* Output on rising edge */
- sb_gpio(GPIOOUTPUT, SPI_MOSI, (mask & buf[i])?1:0);
- /* Clock high */
- sb_gpio(GPIOOUTPUT, SPI_SCK, 1);
- POLL_DELAY();
- }
- }
- return 0;
- }
- static int cur_page = -1;
- static int robo_select_page(int page)
- {
- if (cur_page == page) {
- return 0;
- }
-
- cur_page = page;
- sb_gpio(GPIOOUTPUT, SPI_SS, 0);
- SPI_WRITE8(0x61);
- SPI_WRITE8(R_ROBOSPI_PAGE);
- SPI_WRITE8(page);
- sb_gpio(GPIOOUTPUT, SPI_SS, 1);
- return 0;
- }
- static int robo_reset(void)
- {
- /* Force page change */
- cur_page = -1;
- robo_select_page(0);
- cur_page = -1;
- return 0;
- }
- static int robo_fast_rack_poll()
- {
- uint8_t status;
- int timeout = 10;
- while(timeout-- > 0)
- {
- sb_spi_read(&status, 1);
- if (status & M_SPISTAT_FAST_RACK) {
- return 0;
- }
- POLL_DELAY();
- }
- return -1;
- }
- static int robo_read_reg(int page, int reg, uint8_t * buffer, int length)
- {
- if (length > 8)
- return -1;
-
- robo_select_page(page);
- sb_gpio(GPIOOUTPUT, SPI_SS, 0);
- SPI_WRITE8(0x10);
- SPI_WRITE8(reg);
- if (robo_fast_rack_poll() < 0) // Timeout
- {
- sb_gpio(GPIOOUTPUT, SPI_SS, 1);
- robo_reset();
- return -1;
- }
- // Read registers
- sb_spi_read(buffer, length);
- sb_gpio(GPIOOUTPUT, SPI_SS, 1);
- return 0;
- }
- static int robo_write_reg(int page, int reg, uint8_t * buffer, int length)
- {
- if (length > 8)
- return -1;
-
- robo_select_page(page);
- sb_gpio(GPIOOUTPUT, SPI_SS, 0);
- SPI_WRITE8(0x61);
- SPI_WRITE8(reg);
- sb_spi_write(buffer, length);
- sb_gpio(GPIOOUTPUT, SPI_SS, 1);
- return 0;
- }
- void BCM5324_soft_init(void)
- {
- uint8_t value;
- //MII/IMP PORT (24) CONTROL REGISTER (PAGE 00H/ADDR E8H)
- value = 0xf7;
- robo_write_reg(0x00, 0x00, (uint8_t *)&value, sizeof(value));
-
- //MII/IMP PORT (24) CONTROL REGISTER (PAGE 00H/ADDR E8H)
- value = (1<<4) | (1<<3) | (1<<2);
- robo_write_reg(0x00, 0xe8, (uint8_t *)&value, sizeof(value));
-
- /*GLOBAL MANAGEMENT CONFIGURATION REGISTER (PAGE 02H/ADDR 00H) */
- value = 0x83;
- robo_write_reg(0x02, 0x00, (uint8_t *)&value, sizeof(value));
-
- value = 0x82; //unReset MIB Counters.
- robo_write_reg(0x02, 0x00, (uint8_t *)&value, sizeof(value));
- /* 802.1Q CONTROL 5 REGISTER (PAGE 34H/ADDR 08H) */
- value = 0x03;
- robo_write_reg(0x34, 0x08, (uint8_t *)&value, sizeof(value));
- /* PORT 24 MII PORT STATE OVERRIDE REGISTER (PAGE 00H/ADDR B8H) */
- value = 0xc7;
- robo_write_reg(0x00, 0xb8, (uint8_t *)&value,1);
- }
- static struct semaphore spi_sem;
- static spinlock_t device_spi_lock;
- static int spi_open(struct inode *inode,
- struct file *file)
- {
- return 0;
- }
- static int spi_release(struct inode *inode,
- struct file *file)
- {
- return 0;
- }
- int spi_ioctl(
- struct inode *inode,
- struct file *file,
- unsigned int ioctl_num,/* ioctl 号 */
- unsigned long ioctl_param) /* 对它的参数 */
- {
- uint8_t *temp = (char *)ioctl_param;
- uint8_t * val = temp+4;
- uint8_t page = temp[0];
- uint8_t reg = temp[1];
- uint8_t size = temp[2];
- unsigned long irqflags = 0x00;
-
- down_interruptible(&spi_sem);
- spin_lock_irqsave(&device_spi_lock, irqflags);
-
- switch (ioctl_num) {
- case IOCTL_SPI_READ:
- robo_read_reg(page, reg, val, size);
- break;
- case IOCTL_SPI_WRITE:
- robo_write_reg(page, reg, val, size);
- break;
- default:
- break;
- }
- spin_unlock_irqrestore(&device_spi_lock, irqflags);
- up(&spi_sem);
- return 0;
- }
- struct file_operations Fops = {
- .ioctl = spi_ioctl, /* ioctl */
- .open = spi_open,
- .release = spi_release /* 又名关闭 */
- };
- static int __init spi_module_init(void)
- {
- int ret_val;
- uint8_t cfg;
- ret_val = register_chrdev(SPIDEV_MAJOR, DEVICE_NAME, &Fops);
- if (ret_val < 0) {
- printk("%s failed with %dn",
- "Sorry, registering the character device ", ret_val);
- return ret_val;
- }
- sb_gpio_init();
-
- // BCM5324_soft_init();
-
- sema_init(&spi_sem, 1);
-
- // robo_read_reg(0x34, 0x00, &cfg, 1);
- // printk("cfg 0x%02xn",cfg);
- return 0;
- }
- static int __exit spi_module_cleanup(void)
- {
- int ret;
- ret = unregister_chrdev(SPIDEV_MAJOR, DEVICE_NAME);
- if (ret < 0)
- printk("Error in module_unregister_chrdev: %dn", ret);
-
- return 0;
- }
- module_init(spi_module_init);
- module_exit(spi_module_cleanup);