|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * Copyright (C) KEBA Industrial Automation Gmbh 2024 | 
|  | * | 
|  | * Driver for KEBA system FPGA | 
|  | * | 
|  | * The KEBA system FPGA implements various devices. This driver registers | 
|  | * auxiliary devices for every device within the FPGA. | 
|  | */ | 
|  |  | 
|  | #include <linux/device.h> | 
|  | #include <linux/i2c.h> | 
|  | #include <linux/misc/keba.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/mtd/partitions.h> | 
|  | #include <linux/nvmem-consumer.h> | 
|  | #include <linux/nvmem-provider.h> | 
|  | #include <linux/pci.h> | 
|  | #include <linux/spi/flash.h> | 
|  | #include <linux/spi/spi.h> | 
|  |  | 
|  | #define CP500 "cp500" | 
|  |  | 
|  | #define PCI_VENDOR_ID_KEBA		0xCEBA | 
|  | #define PCI_DEVICE_ID_KEBA_CP035	0x2706 | 
|  | #define PCI_DEVICE_ID_KEBA_CP505	0x2703 | 
|  | #define PCI_DEVICE_ID_KEBA_CP520	0x2696 | 
|  |  | 
|  | #define CP500_SYS_BAR		0 | 
|  | #define CP500_ECM_BAR		1 | 
|  |  | 
|  | /* BAR 0 registers */ | 
|  | #define CP500_VERSION_REG	0x00 | 
|  | #define CP500_RECONFIG_REG	0x11	/* upper 8-bits of STARTUP register */ | 
|  | #define CP500_PRESENT_REG	0x20 | 
|  | #define CP500_AXI_REG		0x40 | 
|  |  | 
|  | /* Bits in BUILD_REG */ | 
|  | #define CP500_BUILD_TEST        0x8000	/* FPGA test version */ | 
|  |  | 
|  | /* Bits in RECONFIG_REG */ | 
|  | #define CP500_RECFG_REQ		0x01	/* reconfigure FPGA on next reset */ | 
|  |  | 
|  | /* Bits in PRESENT_REG */ | 
|  | #define CP500_PRESENT_FAN0	0x01 | 
|  |  | 
|  | /* MSIX */ | 
|  | #define CP500_AXI_MSIX		3 | 
|  | #define CP500_RFB_UART_MSIX	4 | 
|  | #define CP500_DEBUG_UART_MSIX	5 | 
|  | #define CP500_SI1_UART_MSIX	6 | 
|  | #define CP500_NUM_MSIX		8 | 
|  | #define CP500_NUM_MSIX_NO_MMI	2 | 
|  | #define CP500_NUM_MSIX_NO_AXI	3 | 
|  |  | 
|  | /* EEPROM */ | 
|  | #define CP500_EEPROM_DA_OFFSET		0x016F | 
|  | #define CP500_EEPROM_DA_ESC_TYPE_MASK	0x01 | 
|  | #define CP500_EEPROM_ESC_LAN9252	0x00 | 
|  | #define CP500_EEPROM_ESC_ET1100		0x01 | 
|  | #define CP500_EEPROM_CPU_NAME		"cpu_eeprom" | 
|  | #define CP500_EEPROM_CPU_OFFSET		0 | 
|  | #define CP500_EEPROM_CPU_SIZE		3072 | 
|  | #define CP500_EEPROM_USER_NAME		"user_eeprom" | 
|  | #define CP500_EEPROM_USER_OFFSET	3072 | 
|  | #define CP500_EEPROM_USER_SIZE		1024 | 
|  |  | 
|  | /* SPI flash running at full speed */ | 
|  | #define CP500_FLASH_HZ		(33 * 1000 * 1000) | 
|  |  | 
|  | /* LAN9252 */ | 
|  | #define CP500_LAN9252_HZ	(10 * 1000 * 1000) | 
|  |  | 
|  | #define CP500_IS_CP035(dev)	((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP035) | 
|  | #define CP500_IS_CP505(dev)	((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP505) | 
|  | #define CP500_IS_CP520(dev)	((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP520) | 
|  |  | 
|  | struct cp500_dev_info { | 
|  | off_t offset; | 
|  | size_t size; | 
|  | unsigned int msix; | 
|  | }; | 
|  |  | 
|  | struct cp500_devs { | 
|  | struct cp500_dev_info startup; | 
|  | struct cp500_dev_info spi; | 
|  | struct cp500_dev_info i2c; | 
|  | struct cp500_dev_info fan; | 
|  | struct cp500_dev_info batt; | 
|  | struct cp500_dev_info uart0_rfb; | 
|  | struct cp500_dev_info uart1_dbg; | 
|  | struct cp500_dev_info uart2_si1; | 
|  | }; | 
|  |  | 
|  | /* list of devices within FPGA of CP035 family (CP035, CP056, CP057) */ | 
|  | static struct cp500_devs cp035_devices = { | 
|  | .startup   = { 0x0000, SZ_4K }, | 
|  | .spi       = { 0x1000, SZ_4K }, | 
|  | .i2c       = { 0x4000, SZ_4K }, | 
|  | .fan       = { 0x9000, SZ_4K }, | 
|  | .batt      = { 0xA000, SZ_4K }, | 
|  | .uart0_rfb = { 0xB000, SZ_4K, CP500_RFB_UART_MSIX }, | 
|  | .uart2_si1 = { 0xD000, SZ_4K, CP500_SI1_UART_MSIX }, | 
|  | }; | 
|  |  | 
|  | /* list of devices within FPGA of CP505 family (CP503, CP505, CP507) */ | 
|  | static struct cp500_devs cp505_devices = { | 
|  | .startup   = { 0x0000, SZ_4K }, | 
|  | .spi       = { 0x4000, SZ_4K }, | 
|  | .i2c       = { 0x5000, SZ_4K }, | 
|  | .fan       = { 0x9000, SZ_4K }, | 
|  | .batt      = { 0xA000, SZ_4K }, | 
|  | .uart0_rfb = { 0xB000, SZ_4K, CP500_RFB_UART_MSIX }, | 
|  | .uart2_si1 = { 0xD000, SZ_4K, CP500_SI1_UART_MSIX }, | 
|  | }; | 
|  |  | 
|  | /* list of devices within FPGA of CP520 family (CP520, CP530) */ | 
|  | static struct cp500_devs cp520_devices = { | 
|  | .startup   = { 0x0000, SZ_4K }, | 
|  | .spi       = { 0x4000, SZ_4K }, | 
|  | .i2c       = { 0x5000, SZ_4K }, | 
|  | .fan       = { 0x8000, SZ_4K }, | 
|  | .batt      = { 0x9000, SZ_4K }, | 
|  | .uart0_rfb = { 0xC000, SZ_4K, CP500_RFB_UART_MSIX }, | 
|  | .uart1_dbg = { 0xD000, SZ_4K, CP500_DEBUG_UART_MSIX }, | 
|  | }; | 
|  |  | 
|  | struct cp500_nvmem { | 
|  | struct nvmem_device *base_nvmem; | 
|  | unsigned int offset; | 
|  | struct nvmem_device *nvmem; | 
|  | }; | 
|  |  | 
|  | struct cp500 { | 
|  | struct pci_dev *pci_dev; | 
|  | struct cp500_devs *devs; | 
|  | int msix_num; | 
|  | struct { | 
|  | int major; | 
|  | int minor; | 
|  | int build; | 
|  | } version; | 
|  | struct notifier_block nvmem_notifier; | 
|  | atomic_t nvmem_notified; | 
|  |  | 
|  | /* system FPGA BAR */ | 
|  | resource_size_t sys_hwbase; | 
|  | struct keba_spi_auxdev *spi; | 
|  | struct keba_i2c_auxdev *i2c; | 
|  | struct keba_fan_auxdev *fan; | 
|  | struct keba_batt_auxdev *batt; | 
|  | struct keba_uart_auxdev *uart0_rfb; | 
|  | struct keba_uart_auxdev *uart1_dbg; | 
|  | struct keba_uart_auxdev *uart2_si1; | 
|  |  | 
|  | /* ECM EtherCAT BAR */ | 
|  | resource_size_t ecm_hwbase; | 
|  |  | 
|  | /* NVMEM devices */ | 
|  | struct cp500_nvmem nvmem_cpu; | 
|  | struct cp500_nvmem nvmem_user; | 
|  |  | 
|  | void __iomem *system_startup_addr; | 
|  | }; | 
|  |  | 
|  | /* I2C devices */ | 
|  | #define CP500_EEPROM_ADDR	0x50 | 
|  | static struct i2c_board_info cp500_i2c_info[] = { | 
|  | {	/* temperature sensor */ | 
|  | I2C_BOARD_INFO("emc1403", 0x4c), | 
|  | }, | 
|  | {	/* | 
|  | * CPU EEPROM | 
|  | * CP035 family: CPU board | 
|  | * CP505 family: bridge board | 
|  | * CP520 family: carrier board | 
|  | */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR), | 
|  | }, | 
|  | {	/* interface board EEPROM */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 1), | 
|  | }, | 
|  | {	/* | 
|  | * EEPROM (optional) | 
|  | * CP505 family: CPU board | 
|  | * CP520 family: MMI board | 
|  | */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 2), | 
|  | }, | 
|  | {	/* extension module 0 EEPROM (optional) */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 3), | 
|  | }, | 
|  | {	/* extension module 1 EEPROM (optional) */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 4), | 
|  | }, | 
|  | {	/* extension module 2 EEPROM (optional) */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 5), | 
|  | }, | 
|  | {	/* extension module 3 EEPROM (optional) */ | 
|  | I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 6), | 
|  | } | 
|  | }; | 
|  |  | 
|  | /* SPI devices */ | 
|  | static struct mtd_partition cp500_partitions[] = { | 
|  | { | 
|  | .name       = "system-flash-parts", | 
|  | .size       = MTDPART_SIZ_FULL, | 
|  | .offset     = 0, | 
|  | .mask_flags = 0 | 
|  | } | 
|  | }; | 
|  | static const struct flash_platform_data cp500_w25q32 = { | 
|  | .type     = "w25q32", | 
|  | .name     = "system-flash", | 
|  | .parts    = cp500_partitions, | 
|  | .nr_parts = ARRAY_SIZE(cp500_partitions), | 
|  | }; | 
|  | static const struct flash_platform_data cp500_m25p16 = { | 
|  | .type     = "m25p16", | 
|  | .name     = "system-flash", | 
|  | .parts    = cp500_partitions, | 
|  | .nr_parts = ARRAY_SIZE(cp500_partitions), | 
|  | }; | 
|  | static struct spi_board_info cp500_spi_info[] = { | 
|  | {       /* system FPGA configuration bitstream flash */ | 
|  | .modalias      = "m25p80", | 
|  | .platform_data = &cp500_m25p16, | 
|  | .max_speed_hz  = CP500_FLASH_HZ, | 
|  | .chip_select   = 0, | 
|  | .mode          = SPI_MODE_3, | 
|  | }, {    /* LAN9252 EtherCAT slave controller */ | 
|  | .modalias      = "lan9252", | 
|  | .platform_data = NULL, | 
|  | .max_speed_hz  = CP500_LAN9252_HZ, | 
|  | .chip_select   = 1, | 
|  | .mode          = SPI_MODE_3, | 
|  | } | 
|  | }; | 
|  |  | 
|  | static ssize_t cp500_get_fpga_version(struct cp500 *cp500, char *buf, | 
|  | size_t max_len) | 
|  | { | 
|  | int n; | 
|  |  | 
|  | if (CP500_IS_CP035(cp500)) | 
|  | n = scnprintf(buf, max_len, "CP035"); | 
|  | else if (CP500_IS_CP505(cp500)) | 
|  | n = scnprintf(buf, max_len, "CP505"); | 
|  | else | 
|  | n = scnprintf(buf, max_len, "CP500"); | 
|  |  | 
|  | n += scnprintf(buf + n, max_len - n, "_FPGA_%d.%02d", | 
|  | cp500->version.major, cp500->version.minor); | 
|  |  | 
|  | /* test versions have test bit set */ | 
|  | if (cp500->version.build & CP500_BUILD_TEST) | 
|  | n += scnprintf(buf + n, max_len - n, "Test%d", | 
|  | cp500->version.build & ~CP500_BUILD_TEST); | 
|  |  | 
|  | n += scnprintf(buf + n, max_len - n, "\n"); | 
|  |  | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static ssize_t version_show(struct device *dev, struct device_attribute *attr, | 
|  | char *buf) | 
|  | { | 
|  | struct cp500 *cp500 = dev_get_drvdata(dev); | 
|  |  | 
|  | return cp500_get_fpga_version(cp500, buf, PAGE_SIZE); | 
|  | } | 
|  | static DEVICE_ATTR_RO(version); | 
|  |  | 
|  | static ssize_t keep_cfg_show(struct device *dev, struct device_attribute *attr, | 
|  | char *buf) | 
|  | { | 
|  | struct cp500 *cp500 = dev_get_drvdata(dev); | 
|  | unsigned long keep_cfg = 1; | 
|  |  | 
|  | /* | 
|  | * FPGA configuration stream is kept during reset when RECONFIG bit is | 
|  | * zero | 
|  | */ | 
|  | if (ioread8(cp500->system_startup_addr + CP500_RECONFIG_REG) & | 
|  | CP500_RECFG_REQ) | 
|  | keep_cfg = 0; | 
|  |  | 
|  | return sysfs_emit(buf, "%lu\n", keep_cfg); | 
|  | } | 
|  |  | 
|  | static ssize_t keep_cfg_store(struct device *dev, struct device_attribute *attr, | 
|  | const char *buf, size_t count) | 
|  | { | 
|  | struct cp500 *cp500 = dev_get_drvdata(dev); | 
|  | unsigned long keep_cfg; | 
|  |  | 
|  | if (kstrtoul(buf, 10, &keep_cfg) < 0) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* | 
|  | * In normal operation "keep_cfg" is "1". This means that the FPGA keeps | 
|  | * its configuration stream during a reset. | 
|  | * In case of a firmware update of the FPGA, the configuration stream | 
|  | * needs to be reloaded. This can be done without a powercycle by | 
|  | * writing a "0" into the "keep_cfg" attribute. After a reset/reboot th | 
|  | * new configuration stream will be loaded. | 
|  | */ | 
|  | if (keep_cfg) | 
|  | iowrite8(0, cp500->system_startup_addr + CP500_RECONFIG_REG); | 
|  | else | 
|  | iowrite8(CP500_RECFG_REQ, | 
|  | cp500->system_startup_addr + CP500_RECONFIG_REG); | 
|  |  | 
|  | return count; | 
|  | } | 
|  | static DEVICE_ATTR_RW(keep_cfg); | 
|  |  | 
|  | static struct attribute *cp500_attrs[] = { | 
|  | &dev_attr_version.attr, | 
|  | &dev_attr_keep_cfg.attr, | 
|  | NULL | 
|  | }; | 
|  | ATTRIBUTE_GROUPS(cp500); | 
|  |  | 
|  | static void cp500_i2c_release(struct device *dev) | 
|  | { | 
|  | struct keba_i2c_auxdev *i2c = | 
|  | container_of(dev, struct keba_i2c_auxdev, auxdev.dev); | 
|  |  | 
|  | kfree(i2c); | 
|  | } | 
|  |  | 
|  | static int cp500_register_i2c(struct cp500 *cp500) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | cp500->i2c = kzalloc(sizeof(*cp500->i2c), GFP_KERNEL); | 
|  | if (!cp500->i2c) | 
|  | return -ENOMEM; | 
|  |  | 
|  | cp500->i2c->auxdev.name = "i2c"; | 
|  | cp500->i2c->auxdev.id = 0; | 
|  | cp500->i2c->auxdev.dev.release = cp500_i2c_release; | 
|  | cp500->i2c->auxdev.dev.parent = &cp500->pci_dev->dev; | 
|  | cp500->i2c->io = (struct resource) { | 
|  | /* I2C register area */ | 
|  | .start = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->i2c.offset, | 
|  | .end   = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->i2c.offset + | 
|  | cp500->devs->i2c.size - 1, | 
|  | .flags = IORESOURCE_MEM, | 
|  | }; | 
|  | cp500->i2c->info_size = ARRAY_SIZE(cp500_i2c_info); | 
|  | cp500->i2c->info = cp500_i2c_info; | 
|  |  | 
|  | ret = auxiliary_device_init(&cp500->i2c->auxdev); | 
|  | if (ret) { | 
|  | kfree(cp500->i2c); | 
|  | cp500->i2c = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | ret = __auxiliary_device_add(&cp500->i2c->auxdev, "keba"); | 
|  | if (ret) { | 
|  | auxiliary_device_uninit(&cp500->i2c->auxdev); | 
|  | cp500->i2c = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void cp500_spi_release(struct device *dev) | 
|  | { | 
|  | struct keba_spi_auxdev *spi = | 
|  | container_of(dev, struct keba_spi_auxdev, auxdev.dev); | 
|  |  | 
|  | kfree(spi); | 
|  | } | 
|  |  | 
|  | static int cp500_register_spi(struct cp500 *cp500, u8 esc_type) | 
|  | { | 
|  | int info_size; | 
|  | int ret; | 
|  |  | 
|  | cp500->spi = kzalloc(sizeof(*cp500->spi), GFP_KERNEL); | 
|  | if (!cp500->spi) | 
|  | return -ENOMEM; | 
|  |  | 
|  | if (CP500_IS_CP035(cp500)) | 
|  | cp500_spi_info[0].platform_data = &cp500_w25q32; | 
|  | if (esc_type == CP500_EEPROM_ESC_LAN9252) | 
|  | info_size = ARRAY_SIZE(cp500_spi_info); | 
|  | else | 
|  | info_size = ARRAY_SIZE(cp500_spi_info) - 1; | 
|  |  | 
|  | cp500->spi->auxdev.name = "spi"; | 
|  | cp500->spi->auxdev.id = 0; | 
|  | cp500->spi->auxdev.dev.release = cp500_spi_release; | 
|  | cp500->spi->auxdev.dev.parent = &cp500->pci_dev->dev; | 
|  | cp500->spi->io = (struct resource) { | 
|  | /* SPI register area */ | 
|  | .start = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->spi.offset, | 
|  | .end   = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->spi.offset + | 
|  | cp500->devs->spi.size - 1, | 
|  | .flags = IORESOURCE_MEM, | 
|  | }; | 
|  | cp500->spi->info_size = info_size; | 
|  | cp500->spi->info = cp500_spi_info; | 
|  |  | 
|  | ret = auxiliary_device_init(&cp500->spi->auxdev); | 
|  | if (ret) { | 
|  | kfree(cp500->spi); | 
|  | cp500->spi = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | ret = __auxiliary_device_add(&cp500->spi->auxdev, "keba"); | 
|  | if (ret) { | 
|  | auxiliary_device_uninit(&cp500->spi->auxdev); | 
|  | cp500->spi = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void cp500_fan_release(struct device *dev) | 
|  | { | 
|  | struct keba_fan_auxdev *fan = | 
|  | container_of(dev, struct keba_fan_auxdev, auxdev.dev); | 
|  |  | 
|  | kfree(fan); | 
|  | } | 
|  |  | 
|  | static int cp500_register_fan(struct cp500 *cp500) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | cp500->fan = kzalloc(sizeof(*cp500->fan), GFP_KERNEL); | 
|  | if (!cp500->fan) | 
|  | return -ENOMEM; | 
|  |  | 
|  | cp500->fan->auxdev.name = "fan"; | 
|  | cp500->fan->auxdev.id = 0; | 
|  | cp500->fan->auxdev.dev.release = cp500_fan_release; | 
|  | cp500->fan->auxdev.dev.parent = &cp500->pci_dev->dev; | 
|  | cp500->fan->io = (struct resource) { | 
|  | /* fan register area */ | 
|  | .start = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->fan.offset, | 
|  | .end   = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->fan.offset + | 
|  | cp500->devs->fan.size - 1, | 
|  | .flags = IORESOURCE_MEM, | 
|  | }; | 
|  |  | 
|  | ret = auxiliary_device_init(&cp500->fan->auxdev); | 
|  | if (ret) { | 
|  | kfree(cp500->fan); | 
|  | cp500->fan = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | ret = __auxiliary_device_add(&cp500->fan->auxdev, "keba"); | 
|  | if (ret) { | 
|  | auxiliary_device_uninit(&cp500->fan->auxdev); | 
|  | cp500->fan = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void cp500_batt_release(struct device *dev) | 
|  | { | 
|  | struct keba_batt_auxdev *fan = | 
|  | container_of(dev, struct keba_batt_auxdev, auxdev.dev); | 
|  |  | 
|  | kfree(fan); | 
|  | } | 
|  |  | 
|  | static int cp500_register_batt(struct cp500 *cp500) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | cp500->batt = kzalloc(sizeof(*cp500->batt), GFP_KERNEL); | 
|  | if (!cp500->batt) | 
|  | return -ENOMEM; | 
|  |  | 
|  | cp500->batt->auxdev.name = "batt"; | 
|  | cp500->batt->auxdev.id = 0; | 
|  | cp500->batt->auxdev.dev.release = cp500_batt_release; | 
|  | cp500->batt->auxdev.dev.parent = &cp500->pci_dev->dev; | 
|  | cp500->batt->io = (struct resource) { | 
|  | /* battery register area */ | 
|  | .start = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->batt.offset, | 
|  | .end   = (resource_size_t) cp500->sys_hwbase + | 
|  | cp500->devs->batt.offset + | 
|  | cp500->devs->batt.size - 1, | 
|  | .flags = IORESOURCE_MEM, | 
|  | }; | 
|  |  | 
|  | ret = auxiliary_device_init(&cp500->batt->auxdev); | 
|  | if (ret) { | 
|  | kfree(cp500->batt); | 
|  | cp500->batt = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | ret = __auxiliary_device_add(&cp500->batt->auxdev, "keba"); | 
|  | if (ret) { | 
|  | auxiliary_device_uninit(&cp500->batt->auxdev); | 
|  | cp500->batt = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void cp500_uart_release(struct device *dev) | 
|  | { | 
|  | struct keba_uart_auxdev *uart = | 
|  | container_of(dev, struct keba_uart_auxdev, auxdev.dev); | 
|  |  | 
|  | kfree(uart); | 
|  | } | 
|  |  | 
|  | static int cp500_register_uart(struct cp500 *cp500, | 
|  | struct keba_uart_auxdev **uart, const char *name, | 
|  | struct cp500_dev_info *info, unsigned int irq) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | *uart = kzalloc(sizeof(**uart), GFP_KERNEL); | 
|  | if (!*uart) | 
|  | return -ENOMEM; | 
|  |  | 
|  | (*uart)->auxdev.name = name; | 
|  | (*uart)->auxdev.id = 0; | 
|  | (*uart)->auxdev.dev.release = cp500_uart_release; | 
|  | (*uart)->auxdev.dev.parent = &cp500->pci_dev->dev; | 
|  | (*uart)->io = (struct resource) { | 
|  | /* UART register area */ | 
|  | .start = (resource_size_t) cp500->sys_hwbase + info->offset, | 
|  | .end   = (resource_size_t) cp500->sys_hwbase + info->offset + | 
|  | info->size - 1, | 
|  | .flags = IORESOURCE_MEM, | 
|  | }; | 
|  | (*uart)->irq = irq; | 
|  |  | 
|  | ret = auxiliary_device_init(&(*uart)->auxdev); | 
|  | if (ret) { | 
|  | kfree(*uart); | 
|  | *uart = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | ret = __auxiliary_device_add(&(*uart)->auxdev, "keba"); | 
|  | if (ret) { | 
|  | auxiliary_device_uninit(&(*uart)->auxdev); | 
|  | *uart = NULL; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int cp500_nvmem_read(void *priv, unsigned int offset, void *val, | 
|  | size_t bytes) | 
|  | { | 
|  | struct cp500_nvmem *nvmem = priv; | 
|  | int ret; | 
|  |  | 
|  | ret = nvmem_device_read(nvmem->base_nvmem, nvmem->offset + offset, | 
|  | bytes, val); | 
|  | if (ret != bytes) | 
|  | return ret; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int cp500_nvmem_write(void *priv, unsigned int offset, void *val, | 
|  | size_t bytes) | 
|  | { | 
|  | struct cp500_nvmem *nvmem = priv; | 
|  | int ret; | 
|  |  | 
|  | ret = nvmem_device_write(nvmem->base_nvmem, nvmem->offset + offset, | 
|  | bytes, val); | 
|  | if (ret != bytes) | 
|  | return ret; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int cp500_nvmem_register(struct cp500 *cp500, | 
|  | struct nvmem_device *base_nvmem) | 
|  | { | 
|  | struct device *dev = &cp500->pci_dev->dev; | 
|  | struct nvmem_config nvmem_config = {}; | 
|  | struct nvmem_device *tmp; | 
|  |  | 
|  | /* | 
|  | * The main EEPROM of CP500 devices is logically split into two EEPROMs. | 
|  | * The first logical EEPROM with 3 kB contains the type label which is | 
|  | * programmed during production of the device. The second logical EEPROM | 
|  | * with 1 kB is not programmed during production and can be used for | 
|  | * arbitrary user data. | 
|  | */ | 
|  |  | 
|  | nvmem_config.dev = dev; | 
|  | nvmem_config.owner = THIS_MODULE; | 
|  | nvmem_config.id = NVMEM_DEVID_NONE; | 
|  | nvmem_config.type = NVMEM_TYPE_EEPROM; | 
|  | nvmem_config.root_only = true; | 
|  | nvmem_config.reg_read = cp500_nvmem_read; | 
|  | nvmem_config.reg_write = cp500_nvmem_write; | 
|  |  | 
|  | cp500->nvmem_cpu.base_nvmem = base_nvmem; | 
|  | cp500->nvmem_cpu.offset = CP500_EEPROM_CPU_OFFSET; | 
|  | nvmem_config.name = CP500_EEPROM_CPU_NAME; | 
|  | nvmem_config.size = CP500_EEPROM_CPU_SIZE; | 
|  | nvmem_config.priv = &cp500->nvmem_cpu; | 
|  | tmp = nvmem_register(&nvmem_config); | 
|  | if (IS_ERR(tmp)) | 
|  | return PTR_ERR(tmp); | 
|  | cp500->nvmem_cpu.nvmem = tmp; | 
|  |  | 
|  | cp500->nvmem_user.base_nvmem = base_nvmem; | 
|  | cp500->nvmem_user.offset = CP500_EEPROM_USER_OFFSET; | 
|  | nvmem_config.name = CP500_EEPROM_USER_NAME; | 
|  | nvmem_config.size = CP500_EEPROM_USER_SIZE; | 
|  | nvmem_config.priv = &cp500->nvmem_user; | 
|  | tmp = nvmem_register(&nvmem_config); | 
|  | if (IS_ERR(tmp)) { | 
|  | nvmem_unregister(cp500->nvmem_cpu.nvmem); | 
|  | cp500->nvmem_cpu.nvmem = NULL; | 
|  |  | 
|  | return PTR_ERR(tmp); | 
|  | } | 
|  | cp500->nvmem_user.nvmem = tmp; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void cp500_nvmem_unregister(struct cp500 *cp500) | 
|  | { | 
|  | int notified; | 
|  |  | 
|  | if (cp500->nvmem_user.nvmem) { | 
|  | nvmem_unregister(cp500->nvmem_user.nvmem); | 
|  | cp500->nvmem_user.nvmem = NULL; | 
|  | } | 
|  | if (cp500->nvmem_cpu.nvmem) { | 
|  | nvmem_unregister(cp500->nvmem_cpu.nvmem); | 
|  | cp500->nvmem_cpu.nvmem = NULL; | 
|  | } | 
|  |  | 
|  | /* CPU and user nvmem use the same base_nvmem, put only once */ | 
|  | notified = atomic_read(&cp500->nvmem_notified); | 
|  | if (notified) | 
|  | nvmem_device_put(cp500->nvmem_cpu.base_nvmem); | 
|  | } | 
|  |  | 
|  | static int cp500_nvmem_match(struct device *dev, const void *data) | 
|  | { | 
|  | const struct cp500 *cp500 = data; | 
|  | struct i2c_client *client; | 
|  |  | 
|  | /* match only CPU EEPROM below the cp500 device */ | 
|  | dev = dev->parent; | 
|  | client = i2c_verify_client(dev); | 
|  | if (!client || client->addr != CP500_EEPROM_ADDR) | 
|  | return 0; | 
|  | while ((dev = dev->parent)) | 
|  | if (dev == &cp500->pci_dev->dev) | 
|  | return 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int cp500_nvmem(struct notifier_block *nb, unsigned long action, | 
|  | void *data) | 
|  | { | 
|  | struct nvmem_device *nvmem; | 
|  | struct cp500 *cp500; | 
|  | struct device *dev; | 
|  | int notified; | 
|  | u8 esc_type; | 
|  | int ret; | 
|  |  | 
|  | if (action != NVMEM_ADD) | 
|  | return NOTIFY_DONE; | 
|  | cp500 = container_of(nb, struct cp500, nvmem_notifier); | 
|  | dev = &cp500->pci_dev->dev; | 
|  |  | 
|  | /* process CPU EEPROM content only once */ | 
|  | notified = atomic_read(&cp500->nvmem_notified); | 
|  | if (notified) | 
|  | return NOTIFY_DONE; | 
|  | nvmem = nvmem_device_find(cp500, cp500_nvmem_match); | 
|  | if (IS_ERR_OR_NULL(nvmem)) | 
|  | return NOTIFY_DONE; | 
|  | if (!atomic_try_cmpxchg_relaxed(&cp500->nvmem_notified, ¬ified, 1)) { | 
|  | nvmem_device_put(nvmem); | 
|  |  | 
|  | return NOTIFY_DONE; | 
|  | } | 
|  |  | 
|  | ret = cp500_nvmem_register(cp500, nvmem); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | ret = nvmem_device_read(nvmem, CP500_EEPROM_DA_OFFSET, sizeof(esc_type), | 
|  | (void *)&esc_type); | 
|  | if (ret != sizeof(esc_type)) { | 
|  | dev_warn(dev, "Failed to read device assembly!\n"); | 
|  |  | 
|  | return NOTIFY_DONE; | 
|  | } | 
|  | esc_type &= CP500_EEPROM_DA_ESC_TYPE_MASK; | 
|  |  | 
|  | if (cp500_register_spi(cp500, esc_type)) | 
|  | dev_warn(dev, "Failed to register SPI!\n"); | 
|  |  | 
|  | return NOTIFY_OK; | 
|  | } | 
|  |  | 
|  | static void cp500_register_auxiliary_devs(struct cp500 *cp500) | 
|  | { | 
|  | struct device *dev = &cp500->pci_dev->dev; | 
|  | u8 present = ioread8(cp500->system_startup_addr + CP500_PRESENT_REG); | 
|  |  | 
|  | if (cp500_register_i2c(cp500)) | 
|  | dev_warn(dev, "Failed to register I2C!\n"); | 
|  | if (present & CP500_PRESENT_FAN0) | 
|  | if (cp500_register_fan(cp500)) | 
|  | dev_warn(dev, "Failed to register fan!\n"); | 
|  | if (cp500_register_batt(cp500)) | 
|  | dev_warn(dev, "Failed to register battery!\n"); | 
|  | if (cp500->devs->uart0_rfb.size && | 
|  | cp500->devs->uart0_rfb.msix < cp500->msix_num) { | 
|  | int irq = pci_irq_vector(cp500->pci_dev, | 
|  | cp500->devs->uart0_rfb.msix); | 
|  |  | 
|  | if (cp500_register_uart(cp500, &cp500->uart0_rfb, "rs485-uart", | 
|  | &cp500->devs->uart0_rfb, irq)) | 
|  | dev_warn(dev, "Failed to register RFB UART!\n"); | 
|  | } | 
|  | if (cp500->devs->uart1_dbg.size && | 
|  | cp500->devs->uart1_dbg.msix < cp500->msix_num) { | 
|  | int irq = pci_irq_vector(cp500->pci_dev, | 
|  | cp500->devs->uart1_dbg.msix); | 
|  |  | 
|  | if (cp500_register_uart(cp500, &cp500->uart1_dbg, "rs232-uart", | 
|  | &cp500->devs->uart1_dbg, irq)) | 
|  | dev_warn(dev, "Failed to register debug UART!\n"); | 
|  | } | 
|  | if (cp500->devs->uart2_si1.size && | 
|  | cp500->devs->uart2_si1.msix < cp500->msix_num) { | 
|  | int irq = pci_irq_vector(cp500->pci_dev, | 
|  | cp500->devs->uart2_si1.msix); | 
|  |  | 
|  | if (cp500_register_uart(cp500, &cp500->uart2_si1, "uart", | 
|  | &cp500->devs->uart2_si1, irq)) | 
|  | dev_warn(dev, "Failed to register SI1 UART!\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void cp500_unregister_dev(struct auxiliary_device *auxdev) | 
|  | { | 
|  | auxiliary_device_delete(auxdev); | 
|  | auxiliary_device_uninit(auxdev); | 
|  | } | 
|  |  | 
|  | static void cp500_unregister_auxiliary_devs(struct cp500 *cp500) | 
|  | { | 
|  | if (cp500->spi) { | 
|  | cp500_unregister_dev(&cp500->spi->auxdev); | 
|  | cp500->spi = NULL; | 
|  | } | 
|  | if (cp500->i2c) { | 
|  | cp500_unregister_dev(&cp500->i2c->auxdev); | 
|  | cp500->i2c = NULL; | 
|  | } | 
|  | if (cp500->fan) { | 
|  | cp500_unregister_dev(&cp500->fan->auxdev); | 
|  | cp500->fan = NULL; | 
|  | } | 
|  | if (cp500->batt) { | 
|  | cp500_unregister_dev(&cp500->batt->auxdev); | 
|  | cp500->batt = NULL; | 
|  | } | 
|  | if (cp500->uart0_rfb) { | 
|  | cp500_unregister_dev(&cp500->uart0_rfb->auxdev); | 
|  | cp500->uart0_rfb = NULL; | 
|  | } | 
|  | if (cp500->uart1_dbg) { | 
|  | cp500_unregister_dev(&cp500->uart1_dbg->auxdev); | 
|  | cp500->uart1_dbg = NULL; | 
|  | } | 
|  | if (cp500->uart2_si1) { | 
|  | cp500_unregister_dev(&cp500->uart2_si1->auxdev); | 
|  | cp500->uart2_si1 = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | static irqreturn_t cp500_axi_handler(int irq, void *dev) | 
|  | { | 
|  | struct cp500 *cp500 = dev; | 
|  | u32 axi_address = ioread32(cp500->system_startup_addr + CP500_AXI_REG); | 
|  |  | 
|  | /* | 
|  | * FPGA signals AXI response error, print AXI address to indicate which | 
|  | * IP core was affected | 
|  | */ | 
|  | dev_err(&cp500->pci_dev->dev, "AXI response error at 0x%08x\n", | 
|  | axi_address); | 
|  |  | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | static int cp500_enable(struct cp500 *cp500) | 
|  | { | 
|  | int axi_irq = -1; | 
|  | int ret; | 
|  |  | 
|  | if (cp500->msix_num > CP500_NUM_MSIX_NO_AXI) { | 
|  | axi_irq = pci_irq_vector(cp500->pci_dev, CP500_AXI_MSIX); | 
|  | ret = request_irq(axi_irq, cp500_axi_handler, 0, | 
|  | CP500, cp500); | 
|  | if (ret != 0) { | 
|  | dev_err(&cp500->pci_dev->dev, | 
|  | "Failed to register AXI response error!\n"); | 
|  | return ret; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void cp500_disable(struct cp500 *cp500) | 
|  | { | 
|  | int axi_irq; | 
|  |  | 
|  | if (cp500->msix_num > CP500_NUM_MSIX_NO_AXI) { | 
|  | axi_irq = pci_irq_vector(cp500->pci_dev, CP500_AXI_MSIX); | 
|  | free_irq(axi_irq, cp500); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int cp500_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) | 
|  | { | 
|  | struct device *dev = &pci_dev->dev; | 
|  | struct resource startup; | 
|  | struct cp500 *cp500; | 
|  | u32 cp500_vers; | 
|  | char buf[64]; | 
|  | int ret; | 
|  |  | 
|  | cp500 = devm_kzalloc(dev, sizeof(*cp500), GFP_KERNEL); | 
|  | if (!cp500) | 
|  | return -ENOMEM; | 
|  | cp500->pci_dev = pci_dev; | 
|  | cp500->sys_hwbase = pci_resource_start(pci_dev, CP500_SYS_BAR); | 
|  | cp500->ecm_hwbase = pci_resource_start(pci_dev, CP500_ECM_BAR); | 
|  | if (!cp500->sys_hwbase || !cp500->ecm_hwbase) | 
|  | return -ENODEV; | 
|  |  | 
|  | if (CP500_IS_CP035(cp500)) | 
|  | cp500->devs = &cp035_devices; | 
|  | else if (CP500_IS_CP505(cp500)) | 
|  | cp500->devs = &cp505_devices; | 
|  | else if (CP500_IS_CP520(cp500)) | 
|  | cp500->devs = &cp520_devices; | 
|  | else | 
|  | return -ENODEV; | 
|  |  | 
|  | ret = pci_enable_device(pci_dev); | 
|  | if (ret) | 
|  | return ret; | 
|  | pci_set_master(pci_dev); | 
|  |  | 
|  | startup = *pci_resource_n(pci_dev, CP500_SYS_BAR); | 
|  | startup.end = startup.start + cp500->devs->startup.size - 1; | 
|  | cp500->system_startup_addr = devm_ioremap_resource(&pci_dev->dev, | 
|  | &startup); | 
|  | if (IS_ERR(cp500->system_startup_addr)) { | 
|  | ret = PTR_ERR(cp500->system_startup_addr); | 
|  | goto out_disable; | 
|  | } | 
|  |  | 
|  | cp500->msix_num = pci_alloc_irq_vectors(pci_dev, CP500_NUM_MSIX_NO_MMI, | 
|  | CP500_NUM_MSIX, PCI_IRQ_MSIX); | 
|  | if (cp500->msix_num < CP500_NUM_MSIX_NO_MMI) { | 
|  | dev_err(&pci_dev->dev, | 
|  | "Hardware does not support enough MSI-X interrupts\n"); | 
|  | ret = -ENODEV; | 
|  | goto out_disable; | 
|  | } | 
|  |  | 
|  | cp500_vers = ioread32(cp500->system_startup_addr + CP500_VERSION_REG); | 
|  | cp500->version.major = (cp500_vers & 0xff); | 
|  | cp500->version.minor = (cp500_vers >> 8) & 0xff; | 
|  | cp500->version.build = (cp500_vers >> 16) & 0xffff; | 
|  | cp500_get_fpga_version(cp500, buf, sizeof(buf)); | 
|  |  | 
|  | dev_info(&pci_dev->dev, "FPGA version %s", buf); | 
|  |  | 
|  | pci_set_drvdata(pci_dev, cp500); | 
|  |  | 
|  | cp500->nvmem_notifier.notifier_call = cp500_nvmem; | 
|  | ret = nvmem_register_notifier(&cp500->nvmem_notifier); | 
|  | if (ret != 0) | 
|  | goto out_free_irq; | 
|  |  | 
|  | ret = cp500_enable(cp500); | 
|  | if (ret != 0) | 
|  | goto out_unregister_nvmem; | 
|  |  | 
|  | cp500_register_auxiliary_devs(cp500); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | out_unregister_nvmem: | 
|  | nvmem_unregister_notifier(&cp500->nvmem_notifier); | 
|  | out_free_irq: | 
|  | pci_free_irq_vectors(pci_dev); | 
|  | out_disable: | 
|  | pci_clear_master(pci_dev); | 
|  | pci_disable_device(pci_dev); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void cp500_remove(struct pci_dev *pci_dev) | 
|  | { | 
|  | struct cp500 *cp500 = pci_get_drvdata(pci_dev); | 
|  |  | 
|  | /* | 
|  | * unregister CPU and user nvmem and put base_nvmem before parent | 
|  | * auxiliary device of base_nvmem is unregistered | 
|  | */ | 
|  | nvmem_unregister_notifier(&cp500->nvmem_notifier); | 
|  | cp500_nvmem_unregister(cp500); | 
|  |  | 
|  | cp500_unregister_auxiliary_devs(cp500); | 
|  |  | 
|  | cp500_disable(cp500); | 
|  |  | 
|  | pci_set_drvdata(pci_dev, 0); | 
|  |  | 
|  | pci_free_irq_vectors(pci_dev); | 
|  |  | 
|  | pci_clear_master(pci_dev); | 
|  | pci_disable_device(pci_dev); | 
|  | } | 
|  |  | 
|  | static struct pci_device_id cp500_ids[] = { | 
|  | { PCI_DEVICE(PCI_VENDOR_ID_KEBA, PCI_DEVICE_ID_KEBA_CP035) }, | 
|  | { PCI_DEVICE(PCI_VENDOR_ID_KEBA, PCI_DEVICE_ID_KEBA_CP505) }, | 
|  | { PCI_DEVICE(PCI_VENDOR_ID_KEBA, PCI_DEVICE_ID_KEBA_CP520) }, | 
|  | { } | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(pci, cp500_ids); | 
|  |  | 
|  | static struct pci_driver cp500_driver = { | 
|  | .name = CP500, | 
|  | .id_table = cp500_ids, | 
|  | .probe = cp500_probe, | 
|  | .remove = cp500_remove, | 
|  | .dev_groups = cp500_groups, | 
|  | }; | 
|  | module_pci_driver(cp500_driver); | 
|  |  | 
|  | MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>"); | 
|  | MODULE_DESCRIPTION("KEBA CP500 system FPGA driver"); | 
|  | MODULE_LICENSE("GPL"); |