//#define MULTICORE_DEBUG 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MC_MFBSP_TX(n) MC_R (0x7000+(n<<8)) /* Буфер передачи данных */ #define MC_MFBSP_RX(n) MC_R (0x7000+(n<<8)) /* Буфер приема данных */ #define MC_MFBSP_CSR(n) MC_R (0x7004+(n<<8)) /* Управление и состояние */ #define MC_MFBSP_DIR(n) MC_R (0x7008+(n<<8)) /* Управление направлением * порта ввода-вывода */ #define MC_MFBSP_GPIO_DR(n) MC_R (0x700C+(n<<8)) /* Данные порта ввода-вывода */ #define MC_MFBSP_TCTR(n) MC_R (0x7010+(n<<8)) /* Управление передатчиком */ #define MC_MFBSP_RCTR(n) MC_R (0x7014+(n<<8)) /* Управление приёмником */ #define MC_MFBSP_TSR(n) MC_R (0x7018+(n<<8)) /* Состояние передатчика */ #define MC_MFBSP_RSR(n) MC_R (0x701C+(n<<8)) /* Состояние приёмника */ #define MC_MFBSP_TCTR_RATE(n) MC_R (0x7020+(n<<8)) /* Управление темпом передачи данных */ #define MC_MFBSP_RCTR_RATE(n) MC_R (0x7024+(n<<8)) /* Управление темпом приёма данных */ #define MAX_PORTS 4 #define DEVNAME "gpio" #define GPIO_MAJOR 250 // Главная структура данных, описывающая один порт GPIO struct gpio { struct device dev; // Ядерная структура для устройства int id; // Номер порта (от 0 до 3) }; // Все порты GPIO struct gpio_set { struct gpio gpio[MAX_PORTS]; // Массив структур для каждого GPIO struct class *gpio_class; // Класс устройств GPIO }; struct gpio_set *gpio_set; // Имена портов char dev_names[4][8] = { "gpio0", "gpio1", "gpio2", "gpio3" }; static ssize_t gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos); static ssize_t gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos); static int gpio_open(struct inode *inode, struct file *file); static int gpio_release(struct inode *inode, struct file *file); static long gpio_ioctl (struct file *file, unsigned int cmd, unsigned long arg); // Доступные файловые операции static struct file_operations gpio_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = gpio_read, .write = gpio_write, .open = gpio_open, .release = gpio_release, .compat_ioctl = gpio_ioctl, .unlocked_ioctl = gpio_ioctl, }; // // Функция чтения данных из файла устройства пользователем // static ssize_t gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned int port = iminor(file->f_dentry->d_inode); unsigned data = MC_MFBSP_GPIO_DR(port); if (count > 2) count = 2; copy_to_user (buf, &data, count); return count; } // // Функция записи данных в файл устройства пользователем // static ssize_t gpio_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned int port = iminor(file->f_dentry->d_inode); unsigned data = 0; if (count > 2) count = 2; copy_from_user (&data, buf, count); if (MC_MFBSP_CSR(port) & MC_MFBSP_SPI_I2S_EN) { MC_MFBSP_GPIO_DR(port) = (data & ~0x3F) | (MC_MFBSP_GPIO_DR(port) & 0x3F); } else { MC_MFBSP_GPIO_DR(port) = data; } return count; } // // Функция-обработчик команд пользователя ioctl // static long gpio_ioctl (struct file *file, unsigned int cmd, unsigned long arg) { unsigned int port = iminor(file->f_dentry->d_inode); switch (cmd) { case GPIO_RESET_SPI_I2S_EN: MC_MFBSP_CSR(port) &= ~MC_MFBSP_SPI_I2S_EN; return 0; case GPIO_SET_DIRECTION: MC_MFBSP_DIR(port) = arg; return 0; case GPIO_GET_DIRECTION: return MC_MFBSP_DIR(port); default: return -ENOTTY; } } // // Открытие порта // static int gpio_open(struct inode *inode, struct file *file) { unsigned int port_num = iminor(inode); // получаем номер порта PDEBUGG ("===gpio_open, port_num = %d\n", port_num); if (port_num >= MAX_PORTS) return -ENXIO; MC_MFBSP_CSR(port_num) &= ~MC_MFBSP_LEN; return 0; } // // Закрытия порта // static int gpio_release(struct inode *inode, struct file *file) { PDEBUGG ("===gpio_release, port_num = %d\n", port_num); return 0; } // // Начальная инициализация одного порта // static int __init gpio_init_port(struct gpio *port, int port_num) { port->id = port_num; port->dev.parent = NULL; //port->dev.bus = &mcbus; port->dev.init_name = dev_names[port_num]; if (device_register (&port->dev) < 0) { printk(DEVNAME ": Unable to register device!\n"); return -ENODEV; } return 0; } // // Инициализация модуля и всех портов GPIO // static int __init gpio_init(void) { int err, i; unsigned clk_en; if ((gpio_set = kmalloc (sizeof (struct gpio_set), GFP_KERNEL)) == NULL) { printk (DEVNAME ": kmalloc failed\n"); err = -ENOMEM; goto out; } memset (gpio_set, 0, sizeof (struct gpio_set)); if (register_chrdev (GPIO_MAJOR, DEVNAME, &gpio_fops)) { printk (DEVNAME ": unable to get char major %d\n", GPIO_MAJOR); err = -ENODEV; goto out_reg; } gpio_set->gpio_class = class_create (THIS_MODULE, "gpio"); if (IS_ERR (gpio_set->gpio_class)) { printk (DEVNAME ": IS_ERR!\n"); err = PTR_ERR (gpio_set->gpio_class); goto out_dev; } MC_CLKEN |= MC_CLKEN_MFBSP; /* ensure that clock for MFBSP is enabled (as recommended in NVCOM documentation) */ clk_en = MC_CLKEN; clk_en |= clk_en; for (i = 0; i < MAX_PORTS; i++) gpio_init_port (&gpio_set->gpio[i], i); printk (DEVNAME ": init successful!\n"); return 0; out_dev: unregister_chrdev (GPIO_MAJOR, DEVNAME); out_reg: kfree (gpio_set); out: return err; } // // Выгрузка модуля // static void __exit gpio_cleanup(void) { class_destroy (gpio_set->gpio_class); unregister_chrdev (GPIO_MAJOR, DEVNAME); kfree (gpio_set); } module_init(gpio_init); module_exit(gpio_cleanup); MODULE_LICENSE("OSL 2.0");