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