Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HSI: Add common DT binding for HSI client devices

Implement and document generic DT bindings for HSI clients.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Tested-By: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>

+261 -2
+44
Documentation/devicetree/bindings/hsi/client-devices.txt
··· 1 + Each HSI port is supposed to have one child node, which 2 + symbols the remote device connected to the HSI port. The 3 + following properties are standardized for HSI clients: 4 + 5 + Required HSI configuration properties: 6 + 7 + - hsi-channel-ids: A list of channel ids 8 + 9 + - hsi-rx-mode: Receiver Bit transmission mode ("stream" or "frame") 10 + - hsi-tx-mode: Transmitter Bit transmission mode ("stream" or "frame") 11 + - hsi-mode: May be used instead hsi-rx-mode and hsi-tx-mode if 12 + the transmission mode is the same for receiver and 13 + transmitter 14 + - hsi-speed-kbps: Max bit transmission speed in kbit/s 15 + - hsi-flow: RX flow type ("synchronized" or "pipeline") 16 + - hsi-arb-mode: Arbitration mode for TX frame ("round-robin", "priority") 17 + 18 + Optional HSI configuration properties: 19 + 20 + - hsi-channel-names: A list with one name per channel specified in the 21 + hsi-channel-ids property 22 + 23 + 24 + Device Tree node example for an HSI client: 25 + 26 + hsi-controller { 27 + hsi-port { 28 + modem: hsi-client { 29 + compatible = "nokia,n900-modem"; 30 + 31 + hsi-channel-ids = <0>, <1>, <2>, <3>; 32 + hsi-channel-names = "mcsaab-control", 33 + "speech-control", 34 + "speech-data", 35 + "mcsaab-data"; 36 + hsi-speed-kbps = <55000>; 37 + hsi-mode = "frame"; 38 + hsi-flow = "synchronized"; 39 + hsi-arb-mode = "round-robin"; 40 + 41 + /* more client specific properties */ 42 + }; 43 + }; 44 + };
+206 -2
drivers/hsi/hsi.c
··· 26 26 #include <linux/slab.h> 27 27 #include <linux/string.h> 28 28 #include <linux/notifier.h> 29 + #include <linux/of.h> 30 + #include <linux/of_device.h> 29 31 #include "hsi_core.h" 30 32 31 33 static ssize_t modalias_show(struct device *dev, ··· 52 50 53 51 static int hsi_bus_match(struct device *dev, struct device_driver *driver) 54 52 { 55 - return strcmp(dev_name(dev), driver->name) == 0; 53 + if (of_driver_match_device(dev, driver)) 54 + return true; 55 + 56 + if (strcmp(dev_name(dev), driver->name) == 0) 57 + return true; 58 + 59 + return false; 56 60 } 57 61 58 62 static struct bus_type hsi_bus_type = { ··· 130 122 hsi_new_client(p, &cl_info->info); 131 123 } 132 124 } 125 + 126 + #ifdef CONFIG_OF 127 + static struct hsi_board_info hsi_char_dev_info = { 128 + .name = "hsi_char", 129 + }; 130 + 131 + static int hsi_of_property_parse_mode(struct device_node *client, char *name, 132 + unsigned int *result) 133 + { 134 + const char *mode; 135 + int err; 136 + 137 + err = of_property_read_string(client, name, &mode); 138 + if (err < 0) 139 + return err; 140 + 141 + if (strcmp(mode, "stream") == 0) 142 + *result = HSI_MODE_STREAM; 143 + else if (strcmp(mode, "frame") == 0) 144 + *result = HSI_MODE_FRAME; 145 + else 146 + return -EINVAL; 147 + 148 + return 0; 149 + } 150 + 151 + static int hsi_of_property_parse_flow(struct device_node *client, char *name, 152 + unsigned int *result) 153 + { 154 + const char *flow; 155 + int err; 156 + 157 + err = of_property_read_string(client, name, &flow); 158 + if (err < 0) 159 + return err; 160 + 161 + if (strcmp(flow, "synchronized") == 0) 162 + *result = HSI_FLOW_SYNC; 163 + else if (strcmp(flow, "pipeline") == 0) 164 + *result = HSI_FLOW_PIPE; 165 + else 166 + return -EINVAL; 167 + 168 + return 0; 169 + } 170 + 171 + static int hsi_of_property_parse_arb_mode(struct device_node *client, 172 + char *name, unsigned int *result) 173 + { 174 + const char *arb_mode; 175 + int err; 176 + 177 + err = of_property_read_string(client, name, &arb_mode); 178 + if (err < 0) 179 + return err; 180 + 181 + if (strcmp(arb_mode, "round-robin") == 0) 182 + *result = HSI_ARB_RR; 183 + else if (strcmp(arb_mode, "priority") == 0) 184 + *result = HSI_ARB_PRIO; 185 + else 186 + return -EINVAL; 187 + 188 + return 0; 189 + } 190 + 191 + static void hsi_add_client_from_dt(struct hsi_port *port, 192 + struct device_node *client) 193 + { 194 + struct hsi_client *cl; 195 + struct hsi_channel channel; 196 + struct property *prop; 197 + char name[32]; 198 + int length, cells, err, i, max_chan, mode; 199 + 200 + cl = kzalloc(sizeof(*cl), GFP_KERNEL); 201 + if (!cl) 202 + return; 203 + 204 + err = of_modalias_node(client, name, sizeof(name)); 205 + if (err) 206 + goto err; 207 + 208 + dev_set_name(&cl->device, "%s", name); 209 + 210 + err = hsi_of_property_parse_mode(client, "hsi-mode", &mode); 211 + if (err) { 212 + err = hsi_of_property_parse_mode(client, "hsi-rx-mode", 213 + &cl->rx_cfg.mode); 214 + if (err) 215 + goto err; 216 + 217 + err = hsi_of_property_parse_mode(client, "hsi-tx-mode", 218 + &cl->tx_cfg.mode); 219 + if (err) 220 + goto err; 221 + } else { 222 + cl->rx_cfg.mode = mode; 223 + cl->tx_cfg.mode = mode; 224 + } 225 + 226 + err = of_property_read_u32(client, "hsi-speed-kbps", 227 + &cl->tx_cfg.speed); 228 + if (err) 229 + goto err; 230 + cl->rx_cfg.speed = cl->tx_cfg.speed; 231 + 232 + err = hsi_of_property_parse_flow(client, "hsi-flow", 233 + &cl->rx_cfg.flow); 234 + if (err) 235 + goto err; 236 + 237 + err = hsi_of_property_parse_arb_mode(client, "hsi-arb-mode", 238 + &cl->rx_cfg.arb_mode); 239 + if (err) 240 + goto err; 241 + 242 + prop = of_find_property(client, "hsi-channel-ids", &length); 243 + if (!prop) { 244 + err = -EINVAL; 245 + goto err; 246 + } 247 + 248 + cells = length / sizeof(u32); 249 + 250 + cl->rx_cfg.num_channels = cells; 251 + cl->tx_cfg.num_channels = cells; 252 + 253 + cl->rx_cfg.channels = kzalloc(cells * sizeof(channel), GFP_KERNEL); 254 + if (!cl->rx_cfg.channels) { 255 + err = -ENOMEM; 256 + goto err; 257 + } 258 + 259 + cl->tx_cfg.channels = kzalloc(cells * sizeof(channel), GFP_KERNEL); 260 + if (!cl->tx_cfg.channels) { 261 + err = -ENOMEM; 262 + goto err2; 263 + } 264 + 265 + max_chan = 0; 266 + for (i = 0; i < cells; i++) { 267 + err = of_property_read_u32_index(client, "hsi-channel-ids", i, 268 + &channel.id); 269 + if (err) 270 + goto err3; 271 + 272 + err = of_property_read_string_index(client, "hsi-channel-names", 273 + i, &channel.name); 274 + if (err) 275 + channel.name = NULL; 276 + 277 + if (channel.id > max_chan) 278 + max_chan = channel.id; 279 + 280 + cl->rx_cfg.channels[i] = channel; 281 + cl->tx_cfg.channels[i] = channel; 282 + } 283 + 284 + cl->rx_cfg.num_hw_channels = max_chan + 1; 285 + cl->tx_cfg.num_hw_channels = max_chan + 1; 286 + 287 + cl->device.bus = &hsi_bus_type; 288 + cl->device.parent = &port->device; 289 + cl->device.release = hsi_client_release; 290 + cl->device.of_node = client; 291 + 292 + if (device_register(&cl->device) < 0) { 293 + pr_err("hsi: failed to register client: %s\n", name); 294 + put_device(&cl->device); 295 + goto err3; 296 + } 297 + 298 + return; 299 + 300 + err3: 301 + kfree(cl->tx_cfg.channels); 302 + err2: 303 + kfree(cl->rx_cfg.channels); 304 + err: 305 + kfree(cl); 306 + pr_err("hsi client: missing or incorrect of property: err=%d\n", err); 307 + } 308 + 309 + void hsi_add_clients_from_dt(struct hsi_port *port, struct device_node *clients) 310 + { 311 + struct device_node *child; 312 + 313 + /* register hsi-char device */ 314 + hsi_new_client(port, &hsi_char_dev_info); 315 + 316 + for_each_available_child_of_node(clients, child) 317 + hsi_add_client_from_dt(port, child); 318 + } 319 + EXPORT_SYMBOL_GPL(hsi_add_clients_from_dt); 320 + #endif 133 321 134 322 int hsi_remove_client(struct device *dev, void *data __maybe_unused) 135 323 { ··· 709 505 EXPORT_SYMBOL_GPL(hsi_unregister_port_event); 710 506 711 507 /** 712 - * hsi_event -Notifies clients about port events 508 + * hsi_event - Notifies clients about port events 713 509 * @port: Port where the event occurred 714 510 * @event: The event type 715 511 *
+11
include/linux/hsi/hsi.h
··· 301 301 int hsi_remove_client(struct device *dev, void *data); 302 302 void hsi_port_unregister_clients(struct hsi_port *port); 303 303 304 + #ifdef CONFIG_OF 305 + void hsi_add_clients_from_dt(struct hsi_port *port, 306 + struct device_node *clients); 307 + #else 308 + static inline void hsi_add_clients_from_dt(struct hsi_port *port, 309 + struct device_node *clients) 310 + { 311 + return; 312 + } 313 + #endif 314 + 304 315 static inline void hsi_controller_set_drvdata(struct hsi_controller *hsi, 305 316 void *data) 306 317 {