how to increase spidev bus speed - linux-device-driver

I want to communicate through SPI from an Up2 6000 and a microcontroller. On the Up2 I am using Ubuntu 20.04 with kernel 5.13 and the PREEMT_RT patch.
Linux up 5.13.0-rt1 #1 SMP PREEMPT_RT Thu Oct 13 12:09:18 CEST 2022 x86_64 x86_64 x86_64 GNU/Linux
Then my program to communicate through SPI sets the speed like this:
int file_desctiptor = open("/dev/spidev1.0", O_RDWR);
if (file_desctiptor < 0) {
return -2;
}
// Set the spi mode
if (ioctl(file_desctiptor, SPI_IOC_WR_MODE, SPI_MODE_1 | SPI_CS_HIGH) < 0) {
close(file_desctiptor);
return -3;
}
// Set the spi speed
uint32_t speed{8000000};
if (ioctl(file_desctiptor, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
close(file_desctiptor);
return -4;
}
But on the oscilloscope I can see the speed of the SCLK signal is 1MHz. However, when I change the speed value for less than 1MHz I can notice the difference on the oscilloscope, so it must be a maximum set somewhere.
To enable spidev on the Up2 6000 I use ACPI overloads. I also modified the max speed here:
/*
* This ASL can be used to declare a spidev device on SPI1 CS0
*/
DefinitionBlock ("", "SSDT", 5, "INTEL", "SPIDEV0", 0x00000001)
{
External (_SB.PC00.SPI1, DeviceObj)
Scope (\_SB.PC00.SPI1)
{
Device (TP0)
{
Name (_HID, "SPT0001") // _HID: Hardware ID
Name (_DDN, "SPI test device connected to CS0") // _DDN: DOS Device Name
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
SpiSerialBusV2 (0x0000, PolarityLow, FourWireMode, 0x08,
ControllerInitiated, 8000000, ClockPolarityLow,
ClockPhaseFirst, "\\_SB.PC00.SPI1",
0x00, ResourceConsumer, , Exclusive,
)
})
}
}
}
But the speed is still 1MHz. Am I missing something else?
Edit:
I have read back the speed using SPI_IOC_RD_MAX_SPEED_HZ and it is 8MHz but still on my logic analyzer I can see 1MHz.
I compiled my kernel with some logs to see what was happening in the drivers and I got this:
Apparently there are two instances of pxa2xx-spi driver, I suppose one is internal and we don't have much access (the first one with frequency 100MHz) and the other one is the one connected to the GPIO (so with frequency maximum limit of 990099 Hz).
Then, the SPT0001 ACPI module tries to modify this frequency to be 8MHz but as it is bigger than the one of the controller the driver does not set it. Finally, I try to open a file descriptor for SPI exchanges at 10MHz and again the driver refuses to open it because the controller has a smaller frequency.
Where is this frequency limit set? I tried compiling the kernel with different configurations but it didn't change. Is it something related to the hardware itself? Or perhaps another ACPI that I am missing?

Related

Why does D2 RAM work correctly even when clock is disabled?

TL;DR: documentation states I have to enable a specific memory region in the microcontroller before I can use it. However, I can use it before enabling it, or even after disabling it. How is this possible?
I'm currently developing an application for the STM32H743 microcontroller. I don't understand how the RAM seems to work correctly while the clock is disabled.
This MCU has multiple memories, spread over multiple power domains:
In D1 domain it has ITCMRAM + DTCMRAM + AXI SRAM (64 + 128 + 512 kB)
In D2 domain it has SRAM1 + SRAM2 + SRAM3 (128 + 128 + 32 kB)
In D3 domain it has SRAM4 + Backup SRAM (64 + 4 kB)
I want to use the SRAM1. In the reference manual (RM0433 Rev. 7) it is stated at page 366 that:
If the CPU wants to use memories located into D2 domain (SRAM1, SRAM2 and SRAM3), it has to enable them.
In the register settings at page 452 it is described how to do this:
RCC AHB2 Clock Register (RCC_AHB2ENR):
SRAM1EN: SRAM1 block enable
Set and reset by software.
When set, this bit indicates that the SRAM1 is allocated by the CPU. It causes the D2 domain to
take into account also the CPU operation modes, i.e. keeping D2 domain in DRun when the CPU is
in CRun.
0: SRAM1 interface clock is disabled. (default after reset)
1: SRAM1 interface clock is enabled.
So, the default value (after reset) is 0, which means the SRAM1 interface is disabled.
In this thread on the STM Community forum the question was why the D2 RAM wasn't working correctly and the solution was to enable the D2 RAM clocks. The "correct" way to do this is in SystemInit() (part of the STM32H7 HAL). In system_stm32h7xx.c we can find the following code parts:
/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to use initialized data in D2 domain SRAM (AHB SRAM)
*/
// #define DATA_IN_D2_SRAM
(...)
void SystemInit(void)
{
(...)
#if defined(DATA_IN_D2_SRAM)
/* in case of initialized data in D2 SRAM (AHB SRAM) , enable the D2 SRAM clock (AHB SRAM clock)
*/
# if defined(RCC_AHB2ENR_D2SRAM3EN)
RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN);
# elif defined(RCC_AHB2ENR_D2SRAM2EN)
RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN);
# else
RCC->AHB2ENR |= (RCC_AHB2ENR_AHBSRAM1EN | RCC_AHB2ENR_AHBSRAM2EN);
# endif /* RCC_AHB2ENR_D2SRAM3EN */
tmpreg = RCC->AHB2ENR;
(void)tmpreg;
#endif /* DATA_IN_D2_SRAM */
(...)
}
So, to use D2 SRAM, the macro DATA_IN_D2_SRAM should be defined (or you must manually enable the clock using __HAL_RCC_D2SRAM1_CLK_ENABLE()).
However, I don't have this macro defined, and even when I manually disable the clocks, the RAM seems to be working perfectly fine.
My main task (I'm running FreeRTOS, and this is the only task right now) is like this:
void main_task(void * argument)
{
__HAL_RCC_D2SRAM1_CLK_DISABLE();
__HAL_RCC_D2SRAM2_CLK_DISABLE();
__HAL_RCC_D2SRAM3_CLK_DISABLE();
mem_test(); // expected to fail, but runs successfully
for (;;) {}
}
The memory test completely fills the D2 SRAM with known data, then calculates a CRC over it. The CRC is correct. I already have verified that the buffer is really placed in the D2 SRAM (memory address 0x30000400 is within the range 0x30000000-0x3001FFFF of SRAM1). The value of RCC->AHB2ENR is confirmed to be 0 (all clocks disabled). I also confirmed that the address of RCC->AHB2ENR is 0x580244DC, as stated in the datasheet.
The data cache is disabled.
What am I missing here? Why is this memory readable and writable when the clocks are disabled?
UPDATE: On request, here is the code of my memory test, from which I conclude that the memory can be written and read successfully:
// NB: The sections are defined in the linker script.
static char test_data_d1[16] __attribute__((section(".RAM_D1_data"))) = "Test data in D1";
static char test_data_d2[16] __attribute__((section(".RAM_D2_data"))) = "Test data in D2";
static char test_data_d3[16] __attribute__((section(".RAM_D3_data"))) = "Test data in D3";
static char buffer_d1[256 * 1024ul] __attribute__((section(".RAM_D1_bss")));
static char buffer_d2[256 * 1024ul] __attribute__((section(".RAM_D2_bss")));
static char buffer_d3[ 32 * 1024ul] __attribute__((section(".RAM_D3_bss")));
static void mem_test(void)
{
// Fill the buffers each with a different test pattern.
fill_buffer_with_test_data(buffer_d1, sizeof(buffer_d1), test_data_d1);
fill_buffer_with_test_data(buffer_d2, sizeof(buffer_d2), test_data_d2);
fill_buffer_with_test_data(buffer_d3, sizeof(buffer_d3), test_data_d3);
uint32_t crc_d1 = crc32b((uint8_t const *)buffer_d1, sizeof(buffer_d1));
uint32_t crc_d2 = crc32b((uint8_t const *)buffer_d2, sizeof(buffer_d2));
uint32_t crc_d3 = crc32b((uint8_t const *)buffer_d3, sizeof(buffer_d3));
printf("CRC buffer_d1 = 0x%08lX\n", crc_d1);
printf("CRC buffer_d2 = 0x%08lX\n", crc_d2);
printf("CRC buffer_d3 = 0x%08lX\n", crc_d3);
assert(0xC29DFAED == crc_d1); // Python: hex(binascii.crc32(16384 * b'Test data in D1\0'))
assert(0x73B70C2A == crc_d2); // Python: hex(binascii.crc32(16384 * b'Test data in D2\0'))
assert(0xC30AE71E == crc_d3); // Python: hex(binascii.crc32(2048 * b'Test data in D3\0'))
}
After lots of testing and investigating I found out that the D2 SRAM was disabled (as documented and expected) in a minimal application using the SysTick and only a few LEDs to make the test results visible. However, when using a timer (TIM1) instead of SysTick, or when enabling a USART, the D2 SRAM was enabled as well, even when I did not enable it in my code. In fact, adding either one of the following lines of code would implicitly enable the D2 SRAM:
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
STM support has confirmed this behavior:
D2 SRAM is activated as soon as any peripheral in D2 is activated. It means that If you enable clock for any peripheral located in D2 domain (AHB1, AHB2, APB1 and APB2), D2 SRAM is active even if RCC->AHB2ENR is 0.
I'm still looking for a reliable source (reference manual) where this behavior is documented, but it seems to be a plausible explanation.
In practice I think this means that the D2 SRAM will almost always be enabled automagically so you don't have to care about it, at least for the most common use cases (e.g. when using any peripheral or the DMA controllers). Only when you want to use the D2 SRAM but none of the D2 peripherals, you would have to manually enable the SRAM clocks. This would also be the case for the startup code, where (if you choose to implement this) the D2 SRAM will be initialized before any of the peripherals are enabled.

Accessing STM32L4 bootloader over USART: No ACK

I'm trying to access the bootloader for a Nucleo L476RG "slave" board.
The "master" board is a Nucleo L496ZG board. In my program, I have a DigitalOut defined on the master board called extBoot0, extReset. These go off to the boot0 and NRST pins on the slave board. Additionally, I have a Serial instance called usart on the master, which is attached to UART2 on the slave board. Also, it appears that there BOOT1 is preset to run the bootloader, i.e. it's asserted low and cannot be changed to run whatever's in SRAM.
Currently, in resetToBootloader, I set BOOT0 high and drop NRST low for 0.1 seconds, and bring it back up high. I've observed that running this function indeed resets the device and prevents the program from running.
In initBootloader, I format the serial per AN2606: 8-bit, even parity, 1 stop bit. I then send 0x7F over that serial bus to the slave board. I'm not getting any response and using a logic analyzer, I've confirmed that the slave is getting it on the right pin and there is no changes in the slave's TX input. What else needs to be done to start the bootloader?
Here's my relevant code:
DigitalOut extBoot0(D7);
DigitalOut extBoot1(D6);
DigitalOut extReset(D5);
Serial usart(/* tx, rx */ D1, D0);
uint8_t rxBuffer[1];
event_callback_t serialEventCb;
void serialCb(int events) {
printf("something happened!\n");
}
void initBootloader() {
wait(5); // just in case?
// Once initialized the USART1 configuration is: 8-bits, even parity and 1 Stop bit
serialEventCb.attach(serialCb);
usart.format(8, SerialBase::Even, 1);
uint8_t buffer[1024];
// write 0x7F
buffer[0] = 0x7F;
usart.write(buffer, 1, 0, 0);
printf("sending cmd\n");
// should ack 0x79
usart.read(rxBuffer, 1, serialEventCb, SERIAL_EVENT_RX_ALL, 0x79);
}
If it helps at all, here's a picture of my board setup.
I believed I solved this by using USART1 instead of USART2. The documentation states that both USART1 and USART2 can be used, but I only receive a 0x79 from USART1.
Additionally, I had to switch from Serial to UARTSerial. The slave first sends an incorrect packet, 0xC0 with an incorrect parity bit. Not really sure why it does that, but it causes the regular Serial instance to not handle the proceeding byte.

STM32L073RZ (rev Z) IAP jump to bootloader (system memory)

I use the STM32L073RZ (Nucleo 64 board).
I would like to jump into the system memory in application programming (IAP).
My code works on the revision B of the STM32L073 microcontroller but fails on the latest revision, rev Z.
I read the errata sheet, no details are given, just a limitation fixed on the dual boot mechanism into system memory according to the BFB2 bit.
Is the system memory no longer supports an IAP jumping to execute its code (to flash firmwares through USB or UART without using the BOOT0 pin) ?
The function is the first line of my main program, it tests if the code has to jump to the booloader:
void jumpBootLoader(void)
{
/* to do jump? */
if ( *((unsigned long *)0x20003FF0) == 0xDEADBEEF )
{
/* erase the label */
*((unsigned long *)0x20003FF0) = 0xCAFEFEED;
/* set stack pointer to the bootloader start address */
__set_MSP(*((uint32_t*)(0x1FF00000)));
/* system memory mapped at 0x00000000 */
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
/* jump to #bootloader + 4 */
((void (*)(void))(*((uint32_t*)(0x1FF00004))))();
}
}
I call these two lines as soon as the BP1 button is pressed to trig the jump operation after resetting the µC:
*((unsigned long *)0x20003FF0) = 0xDEADBEEF;
NVIC_SystemReset();
I use the HSI 16Mhz clock source.
The solution is to jump twice to the system memory.
First Jump to bootloader startup to initialize Data in RAM until the Program counter will returned to Flash by the Dualbank management.
Second Jump: Jump to the Dualbank bypassed address
How to use: User has first to initialize a variable “ Data_Address” (must be an offset Flash sector aligned address) in Flash to distinguish between first/second Jump.
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = Data_Address;
EraseInitStruct.NbPages = 1;
First_jump = *(__IO uint32_t *)(Data_Address);
if (First_jump == 0) {
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Data_Address, 0xAAAAAAAA);
HAL_FLASH_Lock();
/* Reinitialize the Stack pointer and jump to application address */
JumpAddress = *(__IO uint32_t *)(0x1FF00004);
}
if (First_jump != 0) {
HAL_FLASH_Unlock();
HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
HAL_FLASH_Lock();
/* Reinitialize the Stack pointer and jump to application address */
JumpAddress = (0x1FF00369);
}
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t *)(0x1FF00000));
Jump_To_Application();
First important thing: you use 0x1FF0 0000 as the addres where SP is stored, this is correct. Then you use 0x1 FF00 0004 as the address from which you load the function pointer. This is not correct - one zero too many.
Note that using __set_MSP() is generally not such a good idea if you also use MSP as your stack pointer (which you most likely are). The recent definition of this function, which marks "sp" as clobbered register, causes your change to be reverted almost immediately. Incidentally today I was doing exactly the same thing you are doing and I've found that problem. In your assembly listing you'll see that SP is saved into some other register before the msr msp, ... instruction and restored right after that.
Finally I wrote that manually (STM32F4, so different addresses):
constexpr uint32_t systemMemoryBase {0x1fff0000};
asm volatile
(
" msr msp, %[sp] \n"
" bx %[pc] \n"
:: [sp] "r" (*reinterpret_cast<const uint32_t*>(systemMemoryBase)),
[pc] "r" (*reinterpret_cast<const uint32_t*>(systemMemoryBase + 4))
);
BTW - you don't need to set memory remap for the bootloader to work.
Thanks for your help. I have my answer !
The v4.0 bootloader (initial version) does not implement the dual bank mechanism but this feature is supported by v4.1.
Software can jump to bootloader but it will execute the dual boot mechanism.
So the bootloader goes back to bank1 (or bank2 if a code is "valid").
Today it is not possible to bypass the dual bank mechanism to execute the bootloader with my configuration:
The boot0 pin is reset and the protection level is 0 (see "Table 11. Boot pin and BFB2 bit configuration" in the reference manual).
Where is your program counter when you call __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()?
Remapping a memory region while you're executing out of that same region will end poorly! You may need to relocate this code into SRAM, or execute this code with PC set to the fixed FLASH memory mapping (0x0800xxxx).

USB issue SAM3S-EK -> Custom card

I am developing my project with SAM3S-EK demo board. I used USB CDC and MSC Driver with example code and ASF and everything work fine. Now I want to put the code into my custom card (with a SAM3S1B).
But that is my problem. I have assigned the pin and changed the clock config but the device is not recognized by Windows. All of descriptors are equal to zero (according to USBLyser).
Can someone help me ?
That is my clock config file (I have a 16MHz crystal) :
// ===== System Clock (MCK) Source Options
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK
// ===== System Clock (MCK) Prescaler Options (Fmck = Fsys / (SYSCLK_PRES))
#define CONFIG_SYSCLK_PRES SYSCLK_PRES_4
// ===== PLL0 (A) Options (Fpll = (Fclk * PLL_mul) / PLL_div)
// Use mul and div effective values here.
#define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL
#define CONFIG_PLL0_MUL 32
#define CONFIG_PLL0_DIV 2
// ===== PLL1 (B) Options (Fpll = (Fclk * PLL_mul) / PLL_div)
// Use mul and div effective values here.
#define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_12M_RC
#define CONFIG_PLL1_MUL 16
#define CONFIG_PLL1_DIV 2
// ===== USB Clock Source Options (Fusb = FpllX / USB_div)
// Use div effective value here.
//#define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL0
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1
#define CONFIG_USBCLK_DIV 2
// ===== Target frequency (System clock)
// - XTAL frequency: 16MHz
// - System clock source: PLLA
// - System clock prescaler: 4 (divided by 4)
// - PLLA source: XTAL
// - PLLA output: XTAL * 32 / 3
// - System clock is: 16 * 32 / 4 / 2 = 64MHz
// ===== Target frequency (USB Clock)
// - USB clock source: PLLB
// - USB clock divider: 2 (divided by 2)
// - PLLB output: XTAL * 12 / 2
// - USB clock: 16 * 12 / 2 / 2 = 48MHz
Like all USB devices used under Windows, you need to first install a Windows side USB driver that is specific to the device you are attaching.
When you install Atmel Studio 6.2 or newer, it installs a Windows side USB driver for the Atmel ASF USB driver you are using in your firmware. That Windows driver works with my SAM4E target processor. Be aware that it takes a long time to load the driver in Windows. It will appear to have hung. Just give it time, and it will eventually install the driver. You will probably have to respond to a pop-up warning to permit installation of an unsigned driver.
The Windows driver can also be downloaded and installed separately. Use this link:
https://gallery.atmel.com/Products/Details/6272a8fd-68fe-43d8-a990-741878cfe7b6?
Double check your clock rate. I am using the SAM4L part and it requires the PLL to run off of OSC0 to generate a 48 MHz clock. I had the same problem for a while because my ABDACB used the same clock and changed the rate. As I understand it, the plugging in of a USB device senses the single pull up resistor on the pin DP or DN depending on the speed. That is what tells windows (the host) to attempt to communicate. If the clock rate is wrong, the properties in windows all show 0s.

max732x.c I2C IO Expander + GPIO Keys w/ Linux Device Tree not working

I'm working with a Freescale MX6 and a 3.10.31 Freescale modified kernel. I have a Maxim MAX7325 used as an IO expander, which has pushbuttons attached to P0-P2. The interrupt line from the 7325 is attached to the GPIO_3 pad (which I believe is GPIO1_3...)
I set up the 7325 and gpio-keys in the device tree like this:
max7325_reset: max7325-reset {
compatible = "gpio-reset";
reset-gpios = <&gpio5 16 GPIO_ACTIVE_LOW>;
reset-delay-us = <1>;
#reset-cells = <0>;
};
gpio-keys {
compatible = "gpio-keys";
sw2 {
gpios = <&max7325 2 GPIO_ACTIVE_LOW>;
linux,code = <30>; //a
gpio-key,wakeup;
};
};
and
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1_2>;
status = "okay";
max7325: gpio#68 {
compatible = "maxim,max7325";
reg = <0x68>;
gpio-controller;
#gpio-cells = <2>;
resets = <&max7325_reset>;
gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio1>;
interrupts = <3 2>;
};
};
What appears to happen is when probe for the MAX7325 driver is called, client->dev.platform_data is NULL. Because of this, when max732x_irq_setup is called later, it doesn't set up the chip->gpio_chip.to_irq pointer to point at max732x_gpio_to_irq function (presumably because it doesn't have the right info for this to work.) Later, when gpio_keys
tries to config the first input, it fails when it tries to set up the interrupt and none of the other keys get set up.
gpio-keys gpio-keys.20: Unable to get irq number for GPIO 242, error -6
I did determine using the /sys interface that P0 maps to GPIO 240, so yeah, GPIO 242 is the sw2 GPIO-KEY I was trying to set up.
I'm wondering, does this driver not work with a device tree? I don't see it trying to get any device tree properties, but other IO expander drivers I looked at didn't either, so I thought maybe the I2C core is reading the device tree and supposed to fill in the platform_data from there somehow before it calls the driver's probe function (?)
I'm fairly new at this, so any help would be appreciated. =) I did read a few of the Device Tree docs online, but I'm thinking this is something fairly specific that I'm not doing correctly, which they don't cover... (?)
I do have CONFIG_GPIO_MAX732X_IRQ configured in the kernel... and I did at one point try setting the interrupt-controller property for the max7325 I2c1 node, but I wasn't sure that was needed (?)
MAX732x device tree support
Driver you are using won't work with data from device tree. I have added device tree support to this driver and sent it to kernel mailing lists for review, but they are not merged yet. See this thread (total 4 patches):
You can either apply those patches to your branch or wait for them to get into upstream kernel and then cherry-pick them from there (into your branch).
Bindings documentation (see patches above) shows how to create device tree declaration for MAX732x. In your case it may look like this:
&i2c1 {
expander: max7325#68 {
compatible = "maxim,max7325";
reg = <0x68>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&gpio1>;
interrupts = <3 2>;
};
};
Another way for you to use this driver (without patches above) is to specify platform data in board file for your board. I believe it should be one of next files:
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mach-imx6sl.c
arch/arm/mach-imx/mach-imx6sx.c
You can find an example how to do so here: arch/arm/mach-pxa/littleton.c, line 394.
But it may be not reliable way: I tried to do so and had some issues with i2c buses numbers (didn't look too much in that way though). It also looks bad to scatter devices' definitions between board file and dts file. So I strongly recommend you to use patches above.
Answers to questions
What appears to happen is when probe for the MAX7325 driver is called, client->dev.platform_data is NULL.
It happens because driver was binded with device declaration from device tree file rather than from board file. In that case driver should use client->dev.of_node instead of client->dev.platform_data. Just see how it's done in my patch above.
You can read more about how binding/matching/instantiating happens in kernel documentation here:
Documentation/i2c/instantiating-devices
Documentation/devicetree/usage-model.txt
I thought maybe the I2C core is reading the device tree and supposed to fill in the platform_data from there somehow before it calls the driver's probe function (?)
No. When binding is happening, client->irq being automatically populated in I2C core (before driver's probe function being called). Properties like gpio_base and irq_base -- you don't need them in case when data came from device tree.
I did at one point try setting the interrupt-controller property for the max7325 I2c1 node, but I wasn't sure that was needed (?)
MAX7325 issues interrupt to your SoC when it detects changes on input lines (more specifically, on open-drain I/O ports configured as inputs).
So if you want your driver to generate separate interrupts for each input I/O line (so that other drivers can consume them), you should specify "interrupt-controller" and "#interrupt-cells" properties. But for this you need all patches mentioned above to be applied.
Patches status
Now all mentioned patches were merged into upstream kernel (v4.0 and later):
gpio: max732x: Add device tree support
gpio: max732x: Rewrite IRQ code to use irq_domain API
gpio: max732x: Fix possible deadlock
gpio: max732x: Add DT binding documentation
Also notice that there are some new patches were made on top of my patches. You can watch them here.