1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * AMD ISP platform driver for sensor i2-client instantiation 4 * 5 * Copyright 2025 Advanced Micro Devices, Inc. 6 */ 7 8 #include <linux/err.h> 9 #include <linux/i2c.h> 10 #include <linux/module.h> 11 #include <linux/mutex.h> 12 #include <linux/platform_device.h> 13 #include <linux/property.h> 14 #include <linux/string.h> 15 #include <linux/types.h> 16 #include <linux/units.h> 17 18 #define AMDISP_OV05C10_I2C_ADDR 0x10 19 #define AMDISP_OV05C10_HID "OMNI5C10" 20 #define AMDISP_OV05C10_REMOTE_EP_NAME "ov05c10_isp_4_1_1" 21 #define AMD_ISP_PLAT_DRV_NAME "amd-isp4" 22 23 static const struct software_node isp4_mipi1_endpoint_node; 24 static const struct software_node ov05c10_endpoint_node; 25 26 /* 27 * AMD ISP platform info definition to initialize sensor 28 * specific platform configuration to prepare the amdisp 29 * platform. 30 */ 31 struct amdisp_platform_info { 32 struct i2c_board_info board_info; 33 const struct software_node **swnodes; 34 }; 35 36 /* 37 * AMD ISP platform definition to configure the device properties 38 * missing in the ACPI table. 39 */ 40 struct amdisp_platform { 41 const struct amdisp_platform_info *pinfo; 42 struct i2c_board_info board_info; 43 struct notifier_block i2c_nb; 44 struct i2c_client *i2c_dev; 45 struct mutex lock; /* protects i2c client creation */ 46 }; 47 48 /* Root AMD CAMERA SWNODE */ 49 50 /* Root amd camera node definition */ 51 static const struct software_node amd_camera_node = { 52 .name = "amd_camera", 53 }; 54 55 /* ISP4 SWNODE */ 56 57 /* ISP4 OV05C10 camera node definition */ 58 static const struct software_node isp4_node = { 59 .name = "isp4", 60 .parent = &amd_camera_node, 61 }; 62 63 /* 64 * ISP4 Ports node definition. No properties defined for 65 * ports node. 66 */ 67 static const struct software_node isp4_ports = { 68 .name = "ports", 69 .parent = &isp4_node, 70 }; 71 72 /* 73 * ISP4 Port node definition. No properties defined for 74 * port node. 75 */ 76 static const struct software_node isp4_port_node = { 77 .name = "port@0", 78 .parent = &isp4_ports, 79 }; 80 81 /* 82 * ISP4 MIPI1 remote endpoint points to OV05C10 endpoint 83 * node. 84 */ 85 static const struct software_node_ref_args isp4_refs[] = { 86 SOFTWARE_NODE_REFERENCE(&ov05c10_endpoint_node), 87 }; 88 89 /* ISP4 MIPI1 endpoint node properties table */ 90 static const struct property_entry isp4_mipi1_endpoint_props[] = { 91 PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", isp4_refs), 92 { } 93 }; 94 95 /* ISP4 MIPI1 endpoint node definition */ 96 static const struct software_node isp4_mipi1_endpoint_node = { 97 .name = "endpoint", 98 .parent = &isp4_port_node, 99 .properties = isp4_mipi1_endpoint_props, 100 }; 101 102 /* I2C1 SWNODE */ 103 104 /* I2C1 camera node property table */ 105 static const struct property_entry i2c1_camera_props[] = { 106 PROPERTY_ENTRY_U32("clock-frequency", 1 * HZ_PER_MHZ), 107 { } 108 }; 109 110 /* I2C1 camera node definition */ 111 static const struct software_node i2c1_node = { 112 .name = "i2c1", 113 .parent = &amd_camera_node, 114 .properties = i2c1_camera_props, 115 }; 116 117 /* I2C1 camera node property table */ 118 static const struct property_entry ov05c10_camera_props[] = { 119 PROPERTY_ENTRY_U32("clock-frequency", 24 * HZ_PER_MHZ), 120 { } 121 }; 122 123 /* OV05C10 camera node definition */ 124 static const struct software_node ov05c10_camera_node = { 125 .name = AMDISP_OV05C10_HID, 126 .parent = &i2c1_node, 127 .properties = ov05c10_camera_props, 128 }; 129 130 /* 131 * OV05C10 Ports node definition. No properties defined for 132 * ports node for OV05C10. 133 */ 134 static const struct software_node ov05c10_ports = { 135 .name = "ports", 136 .parent = &ov05c10_camera_node, 137 }; 138 139 /* 140 * OV05C10 Port node definition. 141 */ 142 static const struct software_node ov05c10_port_node = { 143 .name = "port@0", 144 .parent = &ov05c10_ports, 145 }; 146 147 /* 148 * OV05C10 remote endpoint points to ISP4 MIPI1 endpoint 149 * node. 150 */ 151 static const struct software_node_ref_args ov05c10_refs[] = { 152 SOFTWARE_NODE_REFERENCE(&isp4_mipi1_endpoint_node), 153 }; 154 155 /* OV05C10 supports one single link frequency */ 156 static const u64 ov05c10_link_freqs[] = { 157 900 * HZ_PER_MHZ, 158 }; 159 160 /* OV05C10 supports only 2-lane configuration */ 161 static const u32 ov05c10_data_lanes[] = { 162 1, 163 2, 164 }; 165 166 /* OV05C10 endpoint node properties table */ 167 static const struct property_entry ov05c10_endpoint_props[] = { 168 PROPERTY_ENTRY_U32("bus-type", 4), 169 PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes", ov05c10_data_lanes, 170 ARRAY_SIZE(ov05c10_data_lanes)), 171 PROPERTY_ENTRY_U64_ARRAY_LEN("link-frequencies", ov05c10_link_freqs, 172 ARRAY_SIZE(ov05c10_link_freqs)), 173 PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", ov05c10_refs), 174 { } 175 }; 176 177 /* OV05C10 endpoint node definition */ 178 static const struct software_node ov05c10_endpoint_node = { 179 .name = "endpoint", 180 .parent = &ov05c10_port_node, 181 .properties = ov05c10_endpoint_props, 182 }; 183 184 /* 185 * AMD Camera swnode graph uses 10 nodes and also its relationship is 186 * fixed to align with the structure that v4l2 and i2c frameworks expects 187 * for successful parsing of fwnodes and its properties with standard names. 188 * 189 * It is only the node property_entries that will vary for each platform 190 * supporting different sensor modules. 191 * 192 * AMD ISP4 SWNODE GRAPH Structure 193 * 194 * amd_camera { 195 * isp4 { 196 * ports { 197 * port@0 { 198 * isp4_mipi1_ep: endpoint { 199 * remote-endpoint = &OMNI5C10_ep; 200 * }; 201 * }; 202 * }; 203 * }; 204 * 205 * i2c1 { 206 * clock-frequency = 1 MHz; 207 * OMNI5C10 { 208 * clock-frequency = 24MHz; 209 * ports { 210 * port@0 { 211 * OMNI5C10_ep: endpoint { 212 * bus-type = 4; 213 * data-lanes = <1 2>; 214 * link-frequencies = 900MHz; 215 * remote-endpoint = &isp4_mipi1; 216 * }; 217 * }; 218 * }; 219 * }; 220 * }; 221 * }; 222 * 223 */ 224 static const struct software_node *amd_isp4_nodes[] = { 225 &amd_camera_node, 226 &isp4_node, 227 &isp4_ports, 228 &isp4_port_node, 229 &isp4_mipi1_endpoint_node, 230 &i2c1_node, 231 &ov05c10_camera_node, 232 &ov05c10_ports, 233 &ov05c10_port_node, 234 &ov05c10_endpoint_node, 235 NULL 236 }; 237 238 /* OV05C10 specific AMD ISP platform configuration */ 239 static const struct amdisp_platform_info ov05c10_platform_config = { 240 .board_info = { 241 .dev_name = "ov05c10", 242 I2C_BOARD_INFO("ov05c10", AMDISP_OV05C10_I2C_ADDR), 243 }, 244 .swnodes = amd_isp4_nodes, 245 }; 246 247 static const struct acpi_device_id amdisp_sensor_ids[] = { 248 { AMDISP_OV05C10_HID, (kernel_ulong_t)&ov05c10_platform_config }, 249 { } 250 }; 251 MODULE_DEVICE_TABLE(acpi, amdisp_sensor_ids); 252 253 static inline bool is_isp_i2c_adapter(struct i2c_adapter *adap) 254 { 255 return !strcmp(adap->owner->name, "i2c_designware_amdisp"); 256 } 257 258 static void instantiate_isp_i2c_client(struct amdisp_platform *isp4_platform, 259 struct i2c_adapter *adap) 260 { 261 struct i2c_board_info *info = &isp4_platform->board_info; 262 struct i2c_client *i2c_dev; 263 264 guard(mutex)(&isp4_platform->lock); 265 266 if (isp4_platform->i2c_dev) 267 return; 268 269 i2c_dev = i2c_new_client_device(adap, info); 270 if (IS_ERR(i2c_dev)) { 271 dev_err(&adap->dev, "error %pe registering isp i2c_client\n", i2c_dev); 272 return; 273 } 274 isp4_platform->i2c_dev = i2c_dev; 275 } 276 277 static int isp_i2c_bus_notify(struct notifier_block *nb, 278 unsigned long action, void *data) 279 { 280 struct amdisp_platform *isp4_platform = 281 container_of(nb, struct amdisp_platform, i2c_nb); 282 struct device *dev = data; 283 struct i2c_client *client; 284 struct i2c_adapter *adap; 285 286 switch (action) { 287 case BUS_NOTIFY_ADD_DEVICE: 288 adap = i2c_verify_adapter(dev); 289 if (!adap) 290 break; 291 if (is_isp_i2c_adapter(adap)) 292 instantiate_isp_i2c_client(isp4_platform, adap); 293 break; 294 case BUS_NOTIFY_REMOVED_DEVICE: 295 client = i2c_verify_client(dev); 296 if (!client) 297 break; 298 299 scoped_guard(mutex, &isp4_platform->lock) { 300 if (isp4_platform->i2c_dev == client) { 301 dev_dbg(&client->adapter->dev, "amdisp i2c_client removed\n"); 302 isp4_platform->i2c_dev = NULL; 303 } 304 } 305 break; 306 default: 307 break; 308 } 309 310 return NOTIFY_DONE; 311 } 312 313 static struct amdisp_platform *prepare_amdisp_platform(struct device *dev, 314 const struct amdisp_platform_info *src) 315 { 316 struct amdisp_platform *isp4_platform; 317 int ret; 318 319 isp4_platform = devm_kzalloc(dev, sizeof(*isp4_platform), GFP_KERNEL); 320 if (!isp4_platform) 321 return ERR_PTR(-ENOMEM); 322 323 ret = devm_mutex_init(dev, &isp4_platform->lock); 324 if (ret) 325 return ERR_PTR(ret); 326 327 isp4_platform->board_info.dev_name = src->board_info.dev_name; 328 strscpy(isp4_platform->board_info.type, src->board_info.type); 329 isp4_platform->board_info.addr = src->board_info.addr; 330 isp4_platform->pinfo = src; 331 332 ret = software_node_register_node_group(src->swnodes); 333 if (ret) 334 return ERR_PTR(ret); 335 336 /* initialize ov05c10_camera_node */ 337 isp4_platform->board_info.swnode = src->swnodes[6]; 338 339 return isp4_platform; 340 } 341 342 static int try_to_instantiate_i2c_client(struct device *dev, void *data) 343 { 344 struct i2c_adapter *adap = i2c_verify_adapter(dev); 345 struct amdisp_platform *isp4_platform = data; 346 347 if (!isp4_platform || !adap) 348 return 0; 349 if (!adap->owner) 350 return 0; 351 352 if (is_isp_i2c_adapter(adap)) 353 instantiate_isp_i2c_client(isp4_platform, adap); 354 355 return 0; 356 } 357 358 static int amd_isp_probe(struct platform_device *pdev) 359 { 360 const struct amdisp_platform_info *pinfo; 361 struct amdisp_platform *isp4_platform; 362 struct acpi_device *adev; 363 int ret; 364 365 pinfo = device_get_match_data(&pdev->dev); 366 if (!pinfo) 367 return dev_err_probe(&pdev->dev, -EINVAL, 368 "failed to get valid ACPI data\n"); 369 370 isp4_platform = prepare_amdisp_platform(&pdev->dev, pinfo); 371 if (IS_ERR(isp4_platform)) 372 return dev_err_probe(&pdev->dev, PTR_ERR(isp4_platform), 373 "failed to prepare AMD ISP platform fwnode\n"); 374 375 isp4_platform->i2c_nb.notifier_call = isp_i2c_bus_notify; 376 ret = bus_register_notifier(&i2c_bus_type, &isp4_platform->i2c_nb); 377 if (ret) 378 goto error_unregister_sw_node; 379 380 adev = ACPI_COMPANION(&pdev->dev); 381 /* initialize root amd_camera_node */ 382 adev->driver_data = (void *)pinfo->swnodes[0]; 383 384 /* check if adapter is already registered and create i2c client instance */ 385 i2c_for_each_dev(isp4_platform, try_to_instantiate_i2c_client); 386 387 platform_set_drvdata(pdev, isp4_platform); 388 return 0; 389 390 error_unregister_sw_node: 391 software_node_unregister_node_group(isp4_platform->pinfo->swnodes); 392 return ret; 393 } 394 395 static void amd_isp_remove(struct platform_device *pdev) 396 { 397 struct amdisp_platform *isp4_platform = platform_get_drvdata(pdev); 398 399 bus_unregister_notifier(&i2c_bus_type, &isp4_platform->i2c_nb); 400 i2c_unregister_device(isp4_platform->i2c_dev); 401 software_node_unregister_node_group(isp4_platform->pinfo->swnodes); 402 } 403 404 static struct platform_driver amd_isp_platform_driver = { 405 .driver = { 406 .name = AMD_ISP_PLAT_DRV_NAME, 407 .acpi_match_table = amdisp_sensor_ids, 408 }, 409 .probe = amd_isp_probe, 410 .remove = amd_isp_remove, 411 }; 412 413 module_platform_driver(amd_isp_platform_driver); 414 415 MODULE_AUTHOR("Benjamin Chan <benjamin.chan@amd.com>"); 416 MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); 417 MODULE_DESCRIPTION("AMD ISP4 Platform Driver"); 418 MODULE_LICENSE("GPL"); 419