Structure
Create a new directory dm163_example to host your new application and driver code. Once we are done, the file structure will look like this:
dm163_example
├── boards
│   └── disco_l475_iot1.overlay
├── CMakeLists.txt
├── dm163_module
│   └── zephyr
│       ├── CMakeLists.txt
│       ├── dm163.c
│       ├── Kconfig
│       └── module.yml
├── dts
│   └── bindings
│       └── siti,dm163.yaml
├── prj.conf
└── src
    └── main.c
(you do not need to create this hierarchy right now, you'll be guided when it is time to do that)
Here are some explanations of the structure:
- You are already familiar with 
CMakeLists.txt,prj.confandsrc/main.c. - The 
dm163_moduledirectory contains the DM163 device driver. - The 
dts/bindingsdirectory contains thesiti,dm163.yamlfile which describes what is permitted and what is required in a node marked compatible with our device driver, whose name is, as you guessed,siti,dm163(from its maker SiTI and its model DM163). boards/disco_l475_iot1.overlaycontains the device-tree part describing how the DM163 device is connected to our board.
From now on, all file names we indicate in the instructions will be relative to the top of the dm163_example folder.
What is in Zephyr's struct device?
A struct device in Zephyr is made of several fields, including:
- A 
configpointer, which points to read-only data describing the configuration gathered from the device tree and theKconfigoptions. In our case, the configuration will be a structure containing information about the pins to use in order to drive the DM163 chip. - A 
datapointer, which points to data describing the current state of the device driver. In our case, it will contain the brightness and color information for the leds. - A 
apipointer, which points to a read-only data structure compatible with the driver we want to be compatible with. Here we want to be compatible with theleddriver API, so ourapifield will be aconst struct led_driver_api * const. 
Most functions will receive a struct device * parameter which you can use to extract the config and data field containing the information you need. For example, to turn on one of the leds controlled by the DM163, you will modify the state of the led in the data structure and send the new led configuration using pins whose configuration is located in the config structure.
There exist other fields to store power management operations if the device can be put to sleep, as well as the initialization function to call to initialize the device.