diff options
author | Gerhard Engleder <eg@keba.com> | 2024-10-11 21:12:55 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2024-10-13 17:16:57 +0200 |
commit | f965d315bcbd65adfe5e3c161e46b5dc0a463f68 (patch) | |
tree | a133af8b9f731c50805271ce66a8addc9441e23c | |
parent | c6576d91955f59450e168096d61b9d1a608ce57a (diff) |
misc: keba: Add fan device
Add support for the fan auxiliary device. This enables monitoring of the
fan.
Signed-off-by: Gerhard Engleder <eg@keba.com>
Link: https://lore.kernel.org/r/20241011191257.19702-7-gerhard@engleder-embedded.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/keba/cp500.c | 83 | ||||
-rw-r--r-- | include/linux/misc/keba.h | 10 |
2 files changed, 84 insertions, 9 deletions
diff --git a/drivers/misc/keba/cp500.c b/drivers/misc/keba/cp500.c index 3cf99eaf45c4..ae3ed1cece32 100644 --- a/drivers/misc/keba/cp500.c +++ b/drivers/misc/keba/cp500.c @@ -32,6 +32,7 @@ /* 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 */ @@ -40,6 +41,9 @@ /* 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_NUM_MSIX 8 @@ -77,27 +81,31 @@ struct cp500_devs { struct cp500_dev_info startup; struct cp500_dev_info spi; struct cp500_dev_info i2c; + struct cp500_dev_info fan; }; /* 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 }, + .startup = { 0x0000, SZ_4K }, + .spi = { 0x1000, SZ_4K }, + .i2c = { 0x4000, SZ_4K }, + .fan = { 0x9000, SZ_4K }, }; /* 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 }, + .startup = { 0x0000, SZ_4K }, + .spi = { 0x4000, SZ_4K }, + .i2c = { 0x5000, SZ_4K }, + .fan = { 0x9000, SZ_4K }, }; /* 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 }, + .startup = { 0x0000, SZ_4K }, + .spi = { 0x4000, SZ_4K }, + .i2c = { 0x5000, SZ_4K }, + .fan = { 0x8000, SZ_4K }, }; struct cp500_nvmem { @@ -121,6 +129,7 @@ struct cp500 { resource_size_t sys_hwbase; struct keba_spi_auxdev *spi; struct keba_i2c_auxdev *i2c; + struct keba_fan_auxdev *fan; /* ECM EtherCAT BAR */ resource_size_t ecm_hwbase; @@ -400,6 +409,54 @@ static int cp500_register_spi(struct cp500 *cp500, u8 esc_type) 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 int cp500_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes) { @@ -549,9 +606,13 @@ static int cp500_nvmem(struct notifier_block *nb, unsigned long action, 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"); } static void cp500_unregister_dev(struct auxiliary_device *auxdev) @@ -570,6 +631,10 @@ static void cp500_unregister_auxiliary_devs(struct cp500 *cp500) cp500_unregister_dev(&cp500->i2c->auxdev); cp500->i2c = NULL; } + if (cp500->fan) { + cp500_unregister_dev(&cp500->fan->auxdev); + cp500->fan = NULL; + } } static irqreturn_t cp500_axi_handler(int irq, void *dev) diff --git a/include/linux/misc/keba.h b/include/linux/misc/keba.h index 1bd5409c6f6f..451777acc262 100644 --- a/include/linux/misc/keba.h +++ b/include/linux/misc/keba.h @@ -37,4 +37,14 @@ struct keba_spi_auxdev { struct spi_board_info *info; }; +/** + * struct keba_fan_auxdev - KEBA fan auxiliary device + * @auxdev: auxiliary device object + * @io: address range of fan controller IO memory + */ +struct keba_fan_auxdev { + struct auxiliary_device auxdev; + struct resource io; +}; + #endif /* _LINUX_MISC_KEBA_H */ |