how to retrieve bus pointer from device tree - linux-device-driver

Question:
I'm trying to find a way to retrieve the dev object for an mdio_bus that has been added to the device tree. I'm sure I'm going to be rapidly applying my palm to my forehead when I get past this, but for the life of me, I can't find the answer anywhere. I've seen how to find objects on the bus itself using bus_find_device_by_name(), but I can't seem to find how to get the bus itself.
Background:
We are providing network access to our host using a Micrel KSZ8863 Ethernet switch attached to the MACB on an at919g20. Rather than using the fixed PHY option, I've spoofed MDIO address 0 to be a "fake" PHY representing the fixed MII link to the switch. I'm writing a driver for the switch to receive its interrupts and monitor the outward facing PHYs and control the link state of the "fake" PHY to the host. In order to configure the switch beyond basic MIIM configuration, you need to use SMI on the MDIO bus to access the full array of registers in the switch. Through further tweaking of the mii_read/write functions in the MACB, adding a header to the reg address, I believe I can use the MACB's MDIO/MII controller to do the right thing for SMI requests. Because the bus no longer gets addressed by PHY:REG, I need to be able to issue raw read/write commands straight to the bus from the switch driver. And that brings me back to my question: How do I request the dev object of the mdio_bus from the device tree by name?
Thanks,
Brian

After hunting around, fruitlessly, for a way to retrieve a device pointer to an mii_bus object, I ended up coming up with the following solution. I'm not sure its the best way to go about it, but it seems pretty clean. I basically ended up adding a helper function to mdio_bus.c that allows another driver to search for a bus by name using class_find_device(). I'm sure there is better way to do this, that doesn't involve adding onto the bus' driver, but it doesn't seem like the worst way either.
-Brian
Here are the functions I added to mdio_bus.c:
/**
* mdiobus_match_name - compares specified string to the device name
* #dev: device object to be examined
* #data: pointer to string to compare device name to
*
* Description: matching function used in call to class_find_device() to find
* a device with the specified name
*/
static int mdiobus_match_name( struct device * dev, void * data )
{
const char * name = data;
return sysfs_streq( name, dev_name( dev ) );
}
/**
* mdiobus_find_by_name - Convenience function for retrieving an mii_bus pointer
* by name
* #name: name of the bus being searched for
*/
struct mii_bus * mdiobus_find_by_name( char * name )
{
struct device * dev;
/* search devices registered for with the mdio_bus_class using the device
name as the matching criteria */
dev = class_find_device( &mdio_bus_class,
NULL,
(void *)name,
mdiobus_match_name );
/* return the mii_bus pointer or NULL if none was found */
return dev ? container_of( dev, struct mii_bus, dev ) : NULL;
}
EXPORT_SYMBOL( mdiobus_find_by_name );

Related

QSPI connection on STM32 microcontrollers with other peripherals instead of Flash memories

I will start a project which needs a QSPI protocol. The component I will use is a 16-bit ADC which supports QSPI with all combinations of clock phase and polarity. Unfortunately, I couldn't find a source on the internet that points to QSPI on STM32, which works with other components rather than Flash memories. Now, my question: Can I use STM32's QSPI protocol to communicate with other devices that support QSPI? Or is it just configured to be used for memories?
The ADC component I want to use is: ADS9224R (16-bit, 3MSPS)
Here is the image of the datasheet that illustrates this device supports the full QSPI protocol.
Many thanks
page 33 of the datasheet
The STM32 QSPI can work in several modes. The Memory Mapped mode is specifically designed for memories. The Indirect mode however can be used for any peripheral. In this mode you can specify the format of the commands that are exchanged: presence of an instruction, of an adress, of data, etc...
See register QUADSPI_CCR.
QUADSPI supports indirect mode, where for each data transaction you manually specify command, number of bytes in address part, number of data bytes, number of lines used for each part of the communication and so on. Don't know whether HAL supports all of that, it would probably be more efficient to work directly with QUADSPI registers - there are simply too many levers and controls you need to set up, and if the library is missing something, things may not work as you want, and QUADSPI is pretty unpleasant to debug. Luckily, after initial setup, you probably won't need to change very much in its settings.
In fact, some time ago, when I was learning QUADSPI, I wrote my own indirect read/write for QUADSPI flash. Purely a demo program for myself. With a bit of tweaking it shouldn't be hard to adapt it. From my personal experience, QUADSPI is a little hard at first, I spent a pair of weeks debugging it with logic analyzer until I got it to work. Or maybe it was due to my general inexperience.
Below you can find one of my functions, which can be used after initial setup of QUADSPI. Other communication functions are around the same length. You only need to set some settings in a few registers. Be careful with the order of your register manipulations - there is no "start communication" flag/bit/command. Communication starts automatically when you set some parameters in specific registers. This is explicitly stated in the reference manual, QUADSPI section, which was the only documentation I used to write my code. There is surprisingly limited information on QUADSPI available on the Internet, even less with registers.
Here is a piece from my basic example code on registers:
void QSPI_readMemoryBytesQuad(uint32_t address, uint32_t length, uint8_t destination[]) {
while (QUADSPI->SR & QUADSPI_SR_BUSY); //Make sure no operation is going on
QUADSPI->FCR = QUADSPI_FCR_CTOF | QUADSPI_FCR_CSMF | QUADSPI_FCR_CTCF | QUADSPI_FCR_CTEF; // clear all flags
QUADSPI->DLR = length - 1U; //Set number of bytes to read
QUADSPI->CR = (QUADSPI->CR & ~(QUADSPI_CR_FTHRES)) | (0x00 << QUADSPI_CR_FTHRES_Pos); //Set FIFO threshold to 1
/*
* Set communication configuration register
* Functional mode: Indirect read
* Data mode: 4 Lines
* Instruction mode: 4 Lines
* Address mode: 4 Lines
* Address size: 24 Bits
* Dummy cycles: 6 Cycles
* Instruction: Quad Output Fast Read
*
* Set 24-bit Address
*
*/
QUADSPI->CCR =
(QSPI_FMODE_INDIRECT_READ << QUADSPI_CCR_FMODE_Pos) |
(QIO_QUAD << QUADSPI_CCR_DMODE_Pos) |
(QIO_QUAD << QUADSPI_CCR_IMODE_Pos) |
(QIO_QUAD << QUADSPI_CCR_ADMODE_Pos) |
(QSPI_ADSIZE_24 << QUADSPI_CCR_ADSIZE_Pos) |
(0x06 << QUADSPI_CCR_DCYC_Pos) |
(MT25QL128ABA1EW9_COMMAND_QUAD_OUTPUT_FAST_READ << QUADSPI_CCR_INSTRUCTION_Pos);
QUADSPI->AR = (0xFFFFFF) & address;
/* ---------- Communication Starts Automatically ----------*/
while (QUADSPI->SR & QUADSPI_SR_BUSY) {
if (QUADSPI->SR & QUADSPI_SR_FTF) {
*destination = *((uint8_t*) &(QUADSPI->DR)); //Read a byte from data register, byte access
destination++;
}
}
QUADSPI->FCR = QUADSPI_FCR_CTOF | QUADSPI_FCR_CSMF | QUADSPI_FCR_CTCF | QUADSPI_FCR_CTEF; //Clear flags
}
It is a little crude, but it may be a good starting point for you, and it's well-tested and definitely works. You can find all my functions here (GitHub). Combine it with reading the QUADSPI section of the reference manual, and you should start to get a grasp of how to make it work.
Your job will be to determine what kind of commands and in what format you need to send to your QSPI slave device. That information is available in the device's datasheet. Make sure you send command and address and every other part on the correct number of QUADSPI lines. For example, sometimes you need to have command on 1 line and data on all 4, all in the same transaction. Make sure you set dummy cycles, if they are required for some operation. Pay special attention at how you read data that you receive via QUADSPI. You can read it in 32-bit words at once (if incoming data is a whole number of 32-bit words). In my case - in the function provided here - I read it by individual bytes, hence such a scary looking *destination = *((uint8_t*) &(QUADSPI->DR));, where I take an address of the data register, cast it to pointer to uint8_t and dereference it. Otherwise, if you read DR just as QUADSPI->DR, your MCU reads 32-bit word for every byte that arrives, and QUADSPI goes crazy and hangs and shows various errors and triggers FIFO threshold flags and stuff. Just be mindful of how you read that register.

HALL Low Level Alternate pull push

I want to Initialize and send a single int using UART in blue_pill (STM32F10C8). Manual ask to set GPIO mode on ALTRN_PULL_PUSH in blue_pill. But Low level HALL library dosn't have such a option. Here is my code for initializing the UART:
void uart2_init()
{
LL_APB1_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
LL_APB1_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE); // ***this line should be corrected***
LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_OUTPUT_50MHz);
LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX);
LL_USART_ConfigCharacter(USART1, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
LL_USART_SetBaudRate (USART1, 8000000, 9600);
LL_USART_Enable(USART1);
}
I need to set pin mode to "LL_GPIO_MODE_ALTERNATE_PUSH_PULL" but the library dosn't provide
it. Can anyone correct me?
I think you should use LL_GPIO_SetPinOutputType(GPIO_TypeDef *GPIOx, uint32_t PinMask, uint32_t OutputType) function.
Which allows You to set output type of pin as :
LL_GPIO_OUTPUT_PUSHPULL
LL_GPIO_OUTPUT_OPENDRAIN
I am highly recommend You to search this kind of information in - UM1850, where You can find a lot of information, for e.g. there is a information about above function on page 807.

How does STM32 demo USB-DFU boot loader check if user code is loaded?

STM32 HAL demo USB-DFU boot loader contains this code:
/* Test if user code is programmed starting from address 0x0800C000 */
if (((*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFC0000) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t *) (USBD_DFU_APP_DEFAULT_ADD + 4);
JumpToApplication = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD);
JumpToApplication();
}
How does this predicate ((*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFC0000) == 0x20000000 determine whether or not user code is loaded on STM32H7A3 MPU?
What is this magic 0x2FFC0000 mask?
It is very simple and a very bad way. It simply checks if at USBD_DFU_APP_DEFAULT_ADD address (where initial stack pointer value should be) the value AND-et with mask is equal to some value.
I personally always add the CRC32 at the end of the app to check if the app is there and if the app is valid.
... determine whether or not user code is loaded on STM32H7A3 MPU?
It does not have anything in common with MPU
This sample code distributed with CubeMX STM32Cube_FW_H7_V1.9.0 package initially verifies if the app start address (stack top) lies in RAM address space - between 0x20000000 and 0x2003FFFF (256k).
For STM32H7A3ZI MPU (e.g. Nucleo-H7A3ZI-Q) this is incorrect because "regular" RAM (not DTCRAM) starts at address 0x24000000 and is 1024k large. It seems that the correct check for this MPU should be: if((stackAddr & 0x24E00000) == 0x24000000) ...
Although I do not quite understand why for this MPU default stack address configured by CubeMX is 0x24100000 which is top RAM address + 1.

STM32 HAL_I2C_Master_Transmit - Why we need to shift address?

after stumbling upon very strange thing I would like to find out if anyone could provide reasonable explanation.
I have SHT31 humidity sensor running on I2C and after trying to run it on STM32F2 it didn't work.
uint8_t __data[5]={0};
__data[0] = SHT31_SOFTRESET >> 8;
__data[1] = SHT31_SOFTRESET & 0xFF;
HAL_I2C_Master_Transmit(&hi2c3,((uint16_t)0x44)<<1,__data,2,1000);
I have opened the function and saw:
/**
* #brief Transmits in master mode an amount of data in blocking mode.
* #param hi2c Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* #param DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
* #param pData Pointer to data buffer
* #param Size Amount of data to be sent
* #param Timeout Timeout duration
* #retval HAL status
*/
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
/* Init tickstart for timeout management*/
uint32_t tickstart = HAL_GetTick();
if (hi2c->State == HAL_I2C_STATE_READY)
....... and it goes ....
So I followed the comment and frustration from my scope (looking why my bits are not going on the wire) and did:
HAL_I2C_Master_Transmit(&hi2c3,((uint16_t)0x44)<<1,__data,2,1000);
Finally my bits are going out and device ACKs me back - voila it works!
But why?? What would be the reason behind putting burden on the programmer to shift the address?
Because the programmer should probably be made aware if he wants to read or write data to or from the I2C slave device.
In common I2C communication the first seven bits of the "address byte" contains the slave address, whereas the last bit is a read/write bit. 0 is write and 1 is read.
In your case, you want to write data to the device (to perform a soft reset) and therefore a simple left shift will do the trick.
It has never been agreed whether an I2C address is to be specified:
such that it needs to be shifted for transmission, or
such that it does not need to be shifted for transmission.
Therefore some device datasheets specify it in variant 1 and some in variant 2. Similarly, some I2C APIs take the address in variant 1 and some in variant 2.
If the device and the API use a different variant, it's the programmer's burden to shift the address.
It creates a lot of confusion and is quite annoying. I doubt it will every be clarified.
Sorry for the late reply, I just bumped my head against this myself. This should be considered a bug but ST refuses to acknowledge it as such. If you research the reference manual for the I2C section, the OAR1 register states that the address is stored in bits 7:1 for 7 bit mode. Bits 0, 8 and 9 are ignored. The HAL routine that sets the address should then shift the 7 LSB's so that bits 6:0 of your address get written to bits 7:1 of the OAR1 register. This doesn't happen. Essentially, because the code was released, it is now a "feature" and not a bug. Another way to look at it is that the address byte that you send to the HAL is left aligned. This is extremely irritating as it is not consistent for 7 and 10 bit addresses.

Confusion over CoreMIDI Destinations

Given the following code if I use the first method in the if branch to obtain a MIDIDestination the code works correctly, and MIDI data is sent. If I use the second method from the else branch, no data is sent.
var client = MIDIClientRef()
var port = MIDIPortRef()
var dest = MIDIEndpointRef()
MIDIClientCreate("jveditor" as CFString, nil, nil, &client)
MIDIOutputPortCreate(client, "output" as CFString, &port)
if false {
dest = MIDIGetDestination(1)
} else {
var device = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(device, 0)
dest = MIDIEntityGetDestination(entity, 0)
}
var name: Unmanaged<CFString>?
MIDIObjectGetStringProperty(dest, kMIDIPropertyDisplayName, &name)
print(name?.takeUnretainedValue() as! String)
var gmOn : [UInt8] = [ 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 ]
var pktlist = MIDIPacketList()
var current = MIDIPacketListInit(&pktlist)
current = MIDIPacketListAdd(&pktlist, MemoryLayout<MIDIPacketList>.stride, current, 0, gmOn.count, &gmOn)
MIDISend(port, dest, &pktlist)
In both cases the printed device name is correct, and the status of every call is noErr.
I have noticed that if I ask for the kMIDIManufacturerName property that I get different results - specifically using the first method I get Generic, from the USB MIDI interface to which the MIDI device is connected, and with the second method I get the value of Roland configured via the Audio MIDI Setup app.
The reason I want to use the second method is specifically so that I can filter out devices that don't have the desired manufacturer name, but as above I can't then get working output.
Can anyone explain the difference between these two methods, and why the latter doesn't work, and ideally offer a suggestion as to how I can work around that?
It sounds like you want to find only the MIDI destination endpoints to talk to a certain manufacturer's devices. Unfortunately that isn't really possible, since there is no protocol for discovering what MIDI devices exist, what their attributes are, and how they are connected to the computer.
(Remember that MIDI is primitive 1980s technology. It doesn't even require bidirectional communication. There are perfectly valid MIDI setups with MIDI devices that you can send data to, but can never receive data from, and vice versa.)
The computer knows what MIDI interfaces are connected to it (for instance, a USB-MIDI interface). CoreMIDI calls these "Devices". You can find out how many there are, how many ports each has, etc. But there is no way to find out anything about the physical MIDI devices like keyboards and synthesizers that are connected to them.
"External devices" are an attempt to get around the discovery problem. They are the things that appear in Audio MIDI Setup when you press the "Add Device" button. That's all!
Ideally your users would create an external device for each physical MIDI device in their setup, enter all the attributes of each one, and set up all the connections in a way that perfectly mirrors their physical MIDI cables.
Unfortunately, in reality:
There may not be any external devices. There is not much benefit to creating them in Audio MIDI Setup, and it's a lot of boring data entry, so most people don't bother.
If there are external devices, you can't trust any of the information that the users added. The manufacturer might not be right, or might be spelled wrong, for instance.
It's pretty unfriendly to force your users to set things up in Audio MIDI Setup before they can use your software. Therefore, no apps do that... and therefore nobody sets anything up in Audio MIDI Setup. It's a chicken-and-egg problem.
Even if there are external devices, your users might want to send MIDI to other endpoints (like virtual endpoints created by other apps) that are not apparently connected to external devices. You should let them do what they want.
The documentation for MIDIGetDevice() makes a good suggestion:
If a client iterates through the devices and entities in the system, it will not ever visit any virtual sources and destinations created by other clients. Also, a device iteration will return devices which are "offline" (were present in the past but are not currently present), while iterations through the system's sources and destinations will not include the endpoints of offline devices.
Thus clients should usually use MIDIGetNumberOfSources, MIDIGetSource, MIDIGetNumberOfDestinations and MIDIGetDestination, rather iterating through devices and entities to locate endpoints.
In other words: use MIDIGetNumberOfDestinations and MIDIGetDestination to get the possible destinations, then let your users pick one of them. That's all.
If you really want to do more:
Given a destination endpoint, you can use MIDIEndpointGetEntity and MIDIEndpointGetDevice to get to the MIDI interface.
Given any MIDI object, you can find its connections to other objects. Use MIDIObjectGetDataProperty to get the value of property kMIDIPropertyConnectionUniqueID, which is an array of the unique IDs of connected objects. Then use MIDIObjectFindByUniqueID to get to the object. The outObjectType will tell you what kind of object it is.
But that's pretty awkward, and you're not guaranteed to find any useful information.
Based on a hint from Kurt Revis's answer, I've found the solution.
The destination that I needed to find is associated with the source of the external device, with the connection between them found using the kMIDIPropertyConnectionUniqueID property of that source.
Replacing the code in the if / else branch in the question with the code below works:
var external = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(external, 0)
var src = MIDIEntityGetSource(entity, 0)
var connID : Int32 = 0
var dest = MIDIObjectRef()
var type = MIDIObjectType.other
MIDIObjectGetIntegerProperty(src, kMIDIPropertyConnectionUniqueID, &connID)
MIDIObjectFindByUniqueID(connID, &dest, &type)
A property dump suggests that the connection Unique ID property is really a data property (perhaps containing multiple IDs) but the resulting CFData appears to be in big-endian format so reading it as an integer property instead seems to work fine.