v4l2-fwnode.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. /*
  2. * V4L2 fwnode binding parsing library
  3. *
  4. * The origins of the V4L2 fwnode library are in V4L2 OF library that
  5. * formerly was located in v4l2-of.c.
  6. *
  7. * Copyright (c) 2016 Intel Corporation.
  8. * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
  9. *
  10. * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
  11. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
  12. *
  13. * Copyright (C) 2012 Renesas Electronics Corp.
  14. * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  15. *
  16. * This program is free software; you can redistribute it and/or modify
  17. * it under the terms of version 2 of the GNU General Public License as
  18. * published by the Free Software Foundation.
  19. */
  20. #include <linux/acpi.h>
  21. #include <linux/kernel.h>
  22. #include <linux/mm.h>
  23. #include <linux/module.h>
  24. #include <linux/of.h>
  25. #include <linux/property.h>
  26. #include <linux/slab.h>
  27. #include <linux/string.h>
  28. #include <linux/types.h>
  29. #include <media/v4l2-async.h>
  30. #include <media/v4l2-fwnode.h>
  31. #include <media/v4l2-subdev.h>
  32. enum v4l2_fwnode_bus_type {
  33. V4L2_FWNODE_BUS_TYPE_GUESS = 0,
  34. V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
  35. V4L2_FWNODE_BUS_TYPE_CSI1,
  36. V4L2_FWNODE_BUS_TYPE_CCP2,
  37. V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
  38. V4L2_FWNODE_BUS_TYPE_PARALLEL,
  39. V4L2_FWNODE_BUS_TYPE_BT656,
  40. NR_OF_V4L2_FWNODE_BUS_TYPE,
  41. };
  42. static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
  43. struct v4l2_fwnode_endpoint *vep)
  44. {
  45. struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
  46. bool have_clk_lane = false;
  47. unsigned int flags = 0, lanes_used = 0;
  48. unsigned int i;
  49. u32 v;
  50. int rval;
  51. rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
  52. if (rval > 0) {
  53. u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
  54. bus->num_data_lanes =
  55. min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
  56. fwnode_property_read_u32_array(fwnode, "data-lanes", array,
  57. bus->num_data_lanes);
  58. for (i = 0; i < bus->num_data_lanes; i++) {
  59. if (lanes_used & BIT(array[i]))
  60. pr_warn("duplicated lane %u in data-lanes\n",
  61. array[i]);
  62. lanes_used |= BIT(array[i]);
  63. bus->data_lanes[i] = array[i];
  64. pr_debug("lane %u position %u\n", i, array[i]);
  65. }
  66. rval = fwnode_property_read_u32_array(fwnode,
  67. "lane-polarities", NULL,
  68. 0);
  69. if (rval > 0) {
  70. if (rval != 1 + bus->num_data_lanes /* clock+data */) {
  71. pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
  72. 1 + bus->num_data_lanes, rval);
  73. return -EINVAL;
  74. }
  75. fwnode_property_read_u32_array(fwnode,
  76. "lane-polarities", array,
  77. 1 + bus->num_data_lanes);
  78. for (i = 0; i < 1 + bus->num_data_lanes; i++) {
  79. bus->lane_polarities[i] = array[i];
  80. pr_debug("lane %u polarity %sinverted",
  81. i, array[i] ? "" : "not ");
  82. }
  83. } else {
  84. pr_debug("no lane polarities defined, assuming not inverted\n");
  85. }
  86. }
  87. if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
  88. if (lanes_used & BIT(v))
  89. pr_warn("duplicated lane %u in clock-lanes\n", v);
  90. lanes_used |= BIT(v);
  91. bus->clock_lane = v;
  92. have_clk_lane = true;
  93. pr_debug("clock lane position %u\n", v);
  94. }
  95. if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
  96. flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
  97. pr_debug("non-continuous clock\n");
  98. } else {
  99. flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
  100. }
  101. bus->flags = flags;
  102. vep->bus_type = V4L2_MBUS_CSI2_DPHY;
  103. return 0;
  104. }
  105. static void v4l2_fwnode_endpoint_parse_parallel_bus(
  106. struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
  107. {
  108. struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
  109. unsigned int flags = 0;
  110. u32 v;
  111. if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
  112. flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
  113. V4L2_MBUS_HSYNC_ACTIVE_LOW;
  114. pr_debug("hsync-active %s\n", v ? "high" : "low");
  115. }
  116. if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
  117. flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
  118. V4L2_MBUS_VSYNC_ACTIVE_LOW;
  119. pr_debug("vsync-active %s\n", v ? "high" : "low");
  120. }
  121. if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
  122. flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
  123. V4L2_MBUS_FIELD_EVEN_LOW;
  124. pr_debug("field-even-active %s\n", v ? "high" : "low");
  125. }
  126. if (flags)
  127. vep->bus_type = V4L2_MBUS_PARALLEL;
  128. else
  129. vep->bus_type = V4L2_MBUS_BT656;
  130. if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
  131. flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
  132. V4L2_MBUS_PCLK_SAMPLE_FALLING;
  133. pr_debug("pclk-sample %s\n", v ? "high" : "low");
  134. }
  135. if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
  136. flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
  137. V4L2_MBUS_DATA_ACTIVE_LOW;
  138. pr_debug("data-active %s\n", v ? "high" : "low");
  139. }
  140. if (fwnode_property_present(fwnode, "slave-mode")) {
  141. pr_debug("slave mode\n");
  142. flags |= V4L2_MBUS_SLAVE;
  143. } else {
  144. flags |= V4L2_MBUS_MASTER;
  145. }
  146. if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
  147. bus->bus_width = v;
  148. pr_debug("bus-width %u\n", v);
  149. }
  150. if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
  151. bus->data_shift = v;
  152. pr_debug("data-shift %u\n", v);
  153. }
  154. if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
  155. flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
  156. V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
  157. pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
  158. }
  159. if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
  160. flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
  161. V4L2_MBUS_DATA_ENABLE_LOW;
  162. pr_debug("data-enable-active %s\n", v ? "high" : "low");
  163. }
  164. bus->flags = flags;
  165. }
  166. static void
  167. v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
  168. struct v4l2_fwnode_endpoint *vep,
  169. u32 bus_type)
  170. {
  171. struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
  172. u32 v;
  173. if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
  174. bus->clock_inv = v;
  175. pr_debug("clock-inv %u\n", v);
  176. }
  177. if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
  178. bus->strobe = v;
  179. pr_debug("strobe %u\n", v);
  180. }
  181. if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
  182. bus->data_lane = v;
  183. pr_debug("data-lanes %u\n", v);
  184. }
  185. if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
  186. bus->clock_lane = v;
  187. pr_debug("clock-lanes %u\n", v);
  188. }
  189. if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2)
  190. vep->bus_type = V4L2_MBUS_CCP2;
  191. else
  192. vep->bus_type = V4L2_MBUS_CSI1;
  193. }
  194. static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
  195. struct v4l2_fwnode_endpoint *vep)
  196. {
  197. u32 bus_type = 0;
  198. int rval;
  199. pr_debug("===== begin V4L2 endpoint properties\n");
  200. fwnode_graph_parse_endpoint(fwnode, &vep->base);
  201. /* Zero fields from bus_type to until the end */
  202. memset(&vep->bus_type, 0, sizeof(*vep) -
  203. offsetof(typeof(*vep), bus_type));
  204. fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
  205. switch (bus_type) {
  206. case V4L2_FWNODE_BUS_TYPE_GUESS:
  207. rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep);
  208. if (rval)
  209. return rval;
  210. /*
  211. * Parse the parallel video bus properties only if none
  212. * of the MIPI CSI-2 specific properties were found.
  213. */
  214. if (vep->bus.mipi_csi2.flags == 0)
  215. v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
  216. break;
  217. case V4L2_FWNODE_BUS_TYPE_CCP2:
  218. case V4L2_FWNODE_BUS_TYPE_CSI1:
  219. v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type);
  220. break;
  221. default:
  222. pr_warn("unsupported bus type %u\n", bus_type);
  223. return -EINVAL;
  224. }
  225. return 0;
  226. }
  227. int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
  228. struct v4l2_fwnode_endpoint *vep)
  229. {
  230. int ret;
  231. ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
  232. pr_debug("===== end V4L2 endpoint properties\n");
  233. return ret;
  234. }
  235. EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
  236. void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
  237. {
  238. if (IS_ERR_OR_NULL(vep))
  239. return;
  240. kfree(vep->link_frequencies);
  241. kfree(vep);
  242. }
  243. EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
  244. struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
  245. struct fwnode_handle *fwnode)
  246. {
  247. struct v4l2_fwnode_endpoint *vep;
  248. int rval;
  249. vep = kzalloc(sizeof(*vep), GFP_KERNEL);
  250. if (!vep)
  251. return ERR_PTR(-ENOMEM);
  252. rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
  253. if (rval < 0)
  254. goto out_err;
  255. rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
  256. NULL, 0);
  257. if (rval > 0) {
  258. unsigned int i;
  259. vep->link_frequencies =
  260. kmalloc_array(rval, sizeof(*vep->link_frequencies),
  261. GFP_KERNEL);
  262. if (!vep->link_frequencies) {
  263. rval = -ENOMEM;
  264. goto out_err;
  265. }
  266. vep->nr_of_link_frequencies = rval;
  267. rval = fwnode_property_read_u64_array(
  268. fwnode, "link-frequencies", vep->link_frequencies,
  269. vep->nr_of_link_frequencies);
  270. if (rval < 0)
  271. goto out_err;
  272. for (i = 0; i < vep->nr_of_link_frequencies; i++)
  273. pr_info("link-frequencies %u value %llu\n", i,
  274. vep->link_frequencies[i]);
  275. }
  276. pr_debug("===== end V4L2 endpoint properties\n");
  277. return vep;
  278. out_err:
  279. v4l2_fwnode_endpoint_free(vep);
  280. return ERR_PTR(rval);
  281. }
  282. EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
  283. int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
  284. struct v4l2_fwnode_link *link)
  285. {
  286. const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
  287. struct fwnode_handle *fwnode;
  288. memset(link, 0, sizeof(*link));
  289. fwnode = fwnode_get_parent(__fwnode);
  290. fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
  291. fwnode = fwnode_get_next_parent(fwnode);
  292. if (is_of_node(fwnode) &&
  293. of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
  294. fwnode = fwnode_get_next_parent(fwnode);
  295. link->local_node = fwnode;
  296. fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
  297. if (!fwnode) {
  298. fwnode_handle_put(fwnode);
  299. return -ENOLINK;
  300. }
  301. fwnode = fwnode_get_parent(fwnode);
  302. fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
  303. fwnode = fwnode_get_next_parent(fwnode);
  304. if (is_of_node(fwnode) &&
  305. of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
  306. fwnode = fwnode_get_next_parent(fwnode);
  307. link->remote_node = fwnode;
  308. return 0;
  309. }
  310. EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
  311. void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
  312. {
  313. fwnode_handle_put(link->local_node);
  314. fwnode_handle_put(link->remote_node);
  315. }
  316. EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
  317. static int v4l2_async_notifier_fwnode_parse_endpoint(
  318. struct device *dev, struct v4l2_async_notifier *notifier,
  319. struct fwnode_handle *endpoint, unsigned int asd_struct_size,
  320. int (*parse_endpoint)(struct device *dev,
  321. struct v4l2_fwnode_endpoint *vep,
  322. struct v4l2_async_subdev *asd))
  323. {
  324. struct v4l2_async_subdev *asd;
  325. struct v4l2_fwnode_endpoint *vep;
  326. int ret = 0;
  327. asd = kzalloc(asd_struct_size, GFP_KERNEL);
  328. if (!asd)
  329. return -ENOMEM;
  330. asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
  331. asd->match.fwnode =
  332. fwnode_graph_get_remote_port_parent(endpoint);
  333. if (!asd->match.fwnode) {
  334. dev_warn(dev, "bad remote port parent\n");
  335. ret = -ENOTCONN;
  336. goto out_err;
  337. }
  338. vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
  339. if (IS_ERR(vep)) {
  340. ret = PTR_ERR(vep);
  341. dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
  342. ret);
  343. goto out_err;
  344. }
  345. ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
  346. if (ret == -ENOTCONN)
  347. dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
  348. vep->base.id);
  349. else if (ret < 0)
  350. dev_warn(dev,
  351. "driver could not parse port@%u/endpoint@%u (%d)\n",
  352. vep->base.port, vep->base.id, ret);
  353. v4l2_fwnode_endpoint_free(vep);
  354. if (ret < 0)
  355. goto out_err;
  356. ret = v4l2_async_notifier_add_subdev(notifier, asd);
  357. if (ret < 0) {
  358. /* not an error if asd already exists */
  359. if (ret == -EEXIST)
  360. ret = 0;
  361. goto out_err;
  362. }
  363. return 0;
  364. out_err:
  365. fwnode_handle_put(asd->match.fwnode);
  366. kfree(asd);
  367. return ret == -ENOTCONN ? 0 : ret;
  368. }
  369. static int __v4l2_async_notifier_parse_fwnode_endpoints(
  370. struct device *dev, struct v4l2_async_notifier *notifier,
  371. size_t asd_struct_size, unsigned int port, bool has_port,
  372. int (*parse_endpoint)(struct device *dev,
  373. struct v4l2_fwnode_endpoint *vep,
  374. struct v4l2_async_subdev *asd))
  375. {
  376. struct fwnode_handle *fwnode;
  377. int ret = 0;
  378. if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
  379. return -EINVAL;
  380. fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
  381. struct fwnode_handle *dev_fwnode;
  382. bool is_available;
  383. dev_fwnode = fwnode_graph_get_port_parent(fwnode);
  384. is_available = fwnode_device_is_available(dev_fwnode);
  385. fwnode_handle_put(dev_fwnode);
  386. if (!is_available)
  387. continue;
  388. if (has_port) {
  389. struct fwnode_endpoint ep;
  390. ret = fwnode_graph_parse_endpoint(fwnode, &ep);
  391. if (ret)
  392. break;
  393. if (ep.port != port)
  394. continue;
  395. }
  396. ret = v4l2_async_notifier_fwnode_parse_endpoint(
  397. dev, notifier, fwnode, asd_struct_size, parse_endpoint);
  398. if (ret < 0)
  399. break;
  400. }
  401. fwnode_handle_put(fwnode);
  402. return ret;
  403. }
  404. int v4l2_async_notifier_parse_fwnode_endpoints(
  405. struct device *dev, struct v4l2_async_notifier *notifier,
  406. size_t asd_struct_size,
  407. int (*parse_endpoint)(struct device *dev,
  408. struct v4l2_fwnode_endpoint *vep,
  409. struct v4l2_async_subdev *asd))
  410. {
  411. return __v4l2_async_notifier_parse_fwnode_endpoints(
  412. dev, notifier, asd_struct_size, 0, false, parse_endpoint);
  413. }
  414. EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
  415. int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
  416. struct device *dev, struct v4l2_async_notifier *notifier,
  417. size_t asd_struct_size, unsigned int port,
  418. int (*parse_endpoint)(struct device *dev,
  419. struct v4l2_fwnode_endpoint *vep,
  420. struct v4l2_async_subdev *asd))
  421. {
  422. return __v4l2_async_notifier_parse_fwnode_endpoints(
  423. dev, notifier, asd_struct_size, port, true, parse_endpoint);
  424. }
  425. EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
  426. /*
  427. * v4l2_fwnode_reference_parse - parse references for async sub-devices
  428. * @dev: the device node the properties of which are parsed for references
  429. * @notifier: the async notifier where the async subdevs will be added
  430. * @prop: the name of the property
  431. *
  432. * Return: 0 on success
  433. * -ENOENT if no entries were found
  434. * -ENOMEM if memory allocation failed
  435. * -EINVAL if property parsing failed
  436. */
  437. static int v4l2_fwnode_reference_parse(
  438. struct device *dev, struct v4l2_async_notifier *notifier,
  439. const char *prop)
  440. {
  441. struct fwnode_reference_args args;
  442. unsigned int index;
  443. int ret;
  444. for (index = 0;
  445. !(ret = fwnode_property_get_reference_args(
  446. dev_fwnode(dev), prop, NULL, 0, index, &args));
  447. index++)
  448. fwnode_handle_put(args.fwnode);
  449. if (!index)
  450. return -ENOENT;
  451. /*
  452. * Note that right now both -ENODATA and -ENOENT may signal
  453. * out-of-bounds access. Return the error in cases other than that.
  454. */
  455. if (ret != -ENOENT && ret != -ENODATA)
  456. return ret;
  457. for (index = 0; !fwnode_property_get_reference_args(
  458. dev_fwnode(dev), prop, NULL, 0, index, &args);
  459. index++) {
  460. struct v4l2_async_subdev *asd;
  461. asd = v4l2_async_notifier_add_fwnode_subdev(
  462. notifier, args.fwnode, sizeof(*asd));
  463. if (IS_ERR(asd)) {
  464. ret = PTR_ERR(asd);
  465. /* not an error if asd already exists */
  466. if (ret == -EEXIST) {
  467. fwnode_handle_put(args.fwnode);
  468. continue;
  469. }
  470. goto error;
  471. }
  472. }
  473. return 0;
  474. error:
  475. fwnode_handle_put(args.fwnode);
  476. return ret;
  477. }
  478. /*
  479. * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
  480. * arguments
  481. * @fwnode: fwnode to read @prop from
  482. * @notifier: notifier for @dev
  483. * @prop: the name of the property
  484. * @index: the index of the reference to get
  485. * @props: the array of integer property names
  486. * @nprops: the number of integer property names in @nprops
  487. *
  488. * First find an fwnode referred to by the reference at @index in @prop.
  489. *
  490. * Then under that fwnode, @nprops times, for each property in @props,
  491. * iteratively follow child nodes starting from fwnode such that they have the
  492. * property in @props array at the index of the child node distance from the
  493. * root node and the value of that property matching with the integer argument
  494. * of the reference, at the same index.
  495. *
  496. * The child fwnode reched at the end of the iteration is then returned to the
  497. * caller.
  498. *
  499. * The core reason for this is that you cannot refer to just any node in ACPI.
  500. * So to refer to an endpoint (easy in DT) you need to refer to a device, then
  501. * provide a list of (property name, property value) tuples where each tuple
  502. * uniquely identifies a child node. The first tuple identifies a child directly
  503. * underneath the device fwnode, the next tuple identifies a child node
  504. * underneath the fwnode identified by the previous tuple, etc. until you
  505. * reached the fwnode you need.
  506. *
  507. * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
  508. *
  509. * Scope (\_SB.PCI0.I2C2)
  510. * {
  511. * Device (CAM0)
  512. * {
  513. * Name (_DSD, Package () {
  514. * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
  515. * Package () {
  516. * Package () {
  517. * "compatible",
  518. * Package () { "nokia,smia" }
  519. * },
  520. * },
  521. * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
  522. * Package () {
  523. * Package () { "port0", "PRT0" },
  524. * }
  525. * })
  526. * Name (PRT0, Package() {
  527. * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
  528. * Package () {
  529. * Package () { "port", 0 },
  530. * },
  531. * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
  532. * Package () {
  533. * Package () { "endpoint0", "EP00" },
  534. * }
  535. * })
  536. * Name (EP00, Package() {
  537. * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
  538. * Package () {
  539. * Package () { "endpoint", 0 },
  540. * Package () {
  541. * "remote-endpoint",
  542. * Package() {
  543. * \_SB.PCI0.ISP, 4, 0
  544. * }
  545. * },
  546. * }
  547. * })
  548. * }
  549. * }
  550. *
  551. * Scope (\_SB.PCI0)
  552. * {
  553. * Device (ISP)
  554. * {
  555. * Name (_DSD, Package () {
  556. * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
  557. * Package () {
  558. * Package () { "port4", "PRT4" },
  559. * }
  560. * })
  561. *
  562. * Name (PRT4, Package() {
  563. * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
  564. * Package () {
  565. * Package () { "port", 4 },
  566. * },
  567. * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
  568. * Package () {
  569. * Package () { "endpoint0", "EP40" },
  570. * }
  571. * })
  572. *
  573. * Name (EP40, Package() {
  574. * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
  575. * Package () {
  576. * Package () { "endpoint", 0 },
  577. * Package () {
  578. * "remote-endpoint",
  579. * Package () {
  580. * \_SB.PCI0.I2C2.CAM0,
  581. * 0, 0
  582. * }
  583. * },
  584. * }
  585. * })
  586. * }
  587. * }
  588. *
  589. * From the EP40 node under ISP device, you could parse the graph remote
  590. * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
  591. *
  592. * @fwnode: fwnode referring to EP40 under ISP.
  593. * @prop: "remote-endpoint"
  594. * @index: 0
  595. * @props: "port", "endpoint"
  596. * @nprops: 2
  597. *
  598. * And you'd get back fwnode referring to EP00 under CAM0.
  599. *
  600. * The same works the other way around: if you use EP00 under CAM0 as the
  601. * fwnode, you'll get fwnode referring to EP40 under ISP.
  602. *
  603. * The same example in DT syntax would look like this:
  604. *
  605. * cam: cam0 {
  606. * compatible = "nokia,smia";
  607. *
  608. * port {
  609. * port = <0>;
  610. * endpoint {
  611. * endpoint = <0>;
  612. * remote-endpoint = <&isp 4 0>;
  613. * };
  614. * };
  615. * };
  616. *
  617. * isp: isp {
  618. * ports {
  619. * port@4 {
  620. * port = <4>;
  621. * endpoint {
  622. * endpoint = <0>;
  623. * remote-endpoint = <&cam 0 0>;
  624. * };
  625. * };
  626. * };
  627. * };
  628. *
  629. * Return: 0 on success
  630. * -ENOENT if no entries (or the property itself) were found
  631. * -EINVAL if property parsing otherwise failed
  632. * -ENOMEM if memory allocation failed
  633. */
  634. static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
  635. struct fwnode_handle *fwnode, const char *prop, unsigned int index,
  636. const char * const *props, unsigned int nprops)
  637. {
  638. struct fwnode_reference_args fwnode_args;
  639. u64 *args = fwnode_args.args;
  640. struct fwnode_handle *child;
  641. int ret;
  642. /*
  643. * Obtain remote fwnode as well as the integer arguments.
  644. *
  645. * Note that right now both -ENODATA and -ENOENT may signal
  646. * out-of-bounds access. Return -ENOENT in that case.
  647. */
  648. ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
  649. index, &fwnode_args);
  650. if (ret)
  651. return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
  652. /*
  653. * Find a node in the tree under the referred fwnode corresponding to
  654. * the integer arguments.
  655. */
  656. fwnode = fwnode_args.fwnode;
  657. while (nprops--) {
  658. u32 val;
  659. /* Loop over all child nodes under fwnode. */
  660. fwnode_for_each_child_node(fwnode, child) {
  661. if (fwnode_property_read_u32(child, *props, &val))
  662. continue;
  663. /* Found property, see if its value matches. */
  664. if (val == *args)
  665. break;
  666. }
  667. fwnode_handle_put(fwnode);
  668. /* No property found; return an error here. */
  669. if (!child) {
  670. fwnode = ERR_PTR(-ENOENT);
  671. break;
  672. }
  673. props++;
  674. args++;
  675. fwnode = child;
  676. }
  677. return fwnode;
  678. }
  679. /*
  680. * v4l2_fwnode_reference_parse_int_props - parse references for async
  681. * sub-devices
  682. * @dev: struct device pointer
  683. * @notifier: notifier for @dev
  684. * @prop: the name of the property
  685. * @props: the array of integer property names
  686. * @nprops: the number of integer properties
  687. *
  688. * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
  689. * property @prop with integer arguments with child nodes matching in properties
  690. * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
  691. * accordingly.
  692. *
  693. * While it is technically possible to use this function on DT, it is only
  694. * meaningful on ACPI. On Device tree you can refer to any node in the tree but
  695. * on ACPI the references are limited to devices.
  696. *
  697. * Return: 0 on success
  698. * -ENOENT if no entries (or the property itself) were found
  699. * -EINVAL if property parsing otherwisefailed
  700. * -ENOMEM if memory allocation failed
  701. */
  702. static int v4l2_fwnode_reference_parse_int_props(
  703. struct device *dev, struct v4l2_async_notifier *notifier,
  704. const char *prop, const char * const *props, unsigned int nprops)
  705. {
  706. struct fwnode_handle *fwnode;
  707. unsigned int index;
  708. int ret;
  709. index = 0;
  710. do {
  711. fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
  712. prop, index,
  713. props, nprops);
  714. if (IS_ERR(fwnode)) {
  715. /*
  716. * Note that right now both -ENODATA and -ENOENT may
  717. * signal out-of-bounds access. Return the error in
  718. * cases other than that.
  719. */
  720. if (PTR_ERR(fwnode) != -ENOENT &&
  721. PTR_ERR(fwnode) != -ENODATA)
  722. return PTR_ERR(fwnode);
  723. break;
  724. }
  725. fwnode_handle_put(fwnode);
  726. index++;
  727. } while (1);
  728. for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
  729. dev_fwnode(dev), prop, index, props,
  730. nprops))); index++) {
  731. struct v4l2_async_subdev *asd;
  732. asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
  733. sizeof(*asd));
  734. if (IS_ERR(asd)) {
  735. ret = PTR_ERR(asd);
  736. /* not an error if asd already exists */
  737. if (ret == -EEXIST) {
  738. fwnode_handle_put(fwnode);
  739. continue;
  740. }
  741. goto error;
  742. }
  743. }
  744. return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
  745. error:
  746. fwnode_handle_put(fwnode);
  747. return ret;
  748. }
  749. int v4l2_async_notifier_parse_fwnode_sensor_common(
  750. struct device *dev, struct v4l2_async_notifier *notifier)
  751. {
  752. static const char * const led_props[] = { "led" };
  753. static const struct {
  754. const char *name;
  755. const char * const *props;
  756. unsigned int nprops;
  757. } props[] = {
  758. { "flash-leds", led_props, ARRAY_SIZE(led_props) },
  759. { "lens-focus", NULL, 0 },
  760. };
  761. unsigned int i;
  762. for (i = 0; i < ARRAY_SIZE(props); i++) {
  763. int ret;
  764. if (props[i].props && is_acpi_node(dev_fwnode(dev)))
  765. ret = v4l2_fwnode_reference_parse_int_props(
  766. dev, notifier, props[i].name,
  767. props[i].props, props[i].nprops);
  768. else
  769. ret = v4l2_fwnode_reference_parse(
  770. dev, notifier, props[i].name);
  771. if (ret && ret != -ENOENT) {
  772. dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
  773. props[i].name, ret);
  774. return ret;
  775. }
  776. }
  777. return 0;
  778. }
  779. EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
  780. int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
  781. {
  782. struct v4l2_async_notifier *notifier;
  783. int ret;
  784. if (WARN_ON(!sd->dev))
  785. return -ENODEV;
  786. notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
  787. if (!notifier)
  788. return -ENOMEM;
  789. v4l2_async_notifier_init(notifier);
  790. ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
  791. notifier);
  792. if (ret < 0)
  793. goto out_cleanup;
  794. ret = v4l2_async_subdev_notifier_register(sd, notifier);
  795. if (ret < 0)
  796. goto out_cleanup;
  797. ret = v4l2_async_register_subdev(sd);
  798. if (ret < 0)
  799. goto out_unregister;
  800. sd->subdev_notifier = notifier;
  801. return 0;
  802. out_unregister:
  803. v4l2_async_notifier_unregister(notifier);
  804. out_cleanup:
  805. v4l2_async_notifier_cleanup(notifier);
  806. kfree(notifier);
  807. return ret;
  808. }
  809. EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
  810. int v4l2_async_register_fwnode_subdev(
  811. struct v4l2_subdev *sd, size_t asd_struct_size,
  812. unsigned int *ports, unsigned int num_ports,
  813. int (*parse_endpoint)(struct device *dev,
  814. struct v4l2_fwnode_endpoint *vep,
  815. struct v4l2_async_subdev *asd))
  816. {
  817. struct v4l2_async_notifier *notifier;
  818. struct device *dev = sd->dev;
  819. struct fwnode_handle *fwnode;
  820. int ret;
  821. if (WARN_ON(!dev))
  822. return -ENODEV;
  823. fwnode = dev_fwnode(dev);
  824. if (!fwnode_device_is_available(fwnode))
  825. return -ENODEV;
  826. notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
  827. if (!notifier)
  828. return -ENOMEM;
  829. v4l2_async_notifier_init(notifier);
  830. if (!ports) {
  831. ret = v4l2_async_notifier_parse_fwnode_endpoints(
  832. dev, notifier, asd_struct_size, parse_endpoint);
  833. if (ret < 0)
  834. goto out_cleanup;
  835. } else {
  836. unsigned int i;
  837. for (i = 0; i < num_ports; i++) {
  838. ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
  839. dev, notifier, asd_struct_size,
  840. ports[i], parse_endpoint);
  841. if (ret < 0)
  842. goto out_cleanup;
  843. }
  844. }
  845. ret = v4l2_async_subdev_notifier_register(sd, notifier);
  846. if (ret < 0)
  847. goto out_cleanup;
  848. ret = v4l2_async_register_subdev(sd);
  849. if (ret < 0)
  850. goto out_unregister;
  851. sd->subdev_notifier = notifier;
  852. return 0;
  853. out_unregister:
  854. v4l2_async_notifier_unregister(notifier);
  855. out_cleanup:
  856. v4l2_async_notifier_cleanup(notifier);
  857. kfree(notifier);
  858. return ret;
  859. }
  860. EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
  861. MODULE_LICENSE("GPL");
  862. MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
  863. MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
  864. MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");