xref: /linux/drivers/dpll/zl3073x/prop.c (revision 12ba92f0a6defd60cb0c518c69fce19d7d27660d)
1a99a9f0eSIvan Vecera // SPDX-License-Identifier: GPL-2.0-only
2a99a9f0eSIvan Vecera 
3a99a9f0eSIvan Vecera #include <linux/array_size.h>
4a99a9f0eSIvan Vecera #include <linux/dev_printk.h>
5a99a9f0eSIvan Vecera #include <linux/err.h>
6a99a9f0eSIvan Vecera #include <linux/errno.h>
7a99a9f0eSIvan Vecera #include <linux/fwnode.h>
8a99a9f0eSIvan Vecera #include <linux/property.h>
9a99a9f0eSIvan Vecera #include <linux/slab.h>
10a99a9f0eSIvan Vecera #include <linux/string.h>
11a99a9f0eSIvan Vecera 
12a99a9f0eSIvan Vecera #include "core.h"
13a99a9f0eSIvan Vecera #include "prop.h"
14a99a9f0eSIvan Vecera 
15a99a9f0eSIvan Vecera /**
16a99a9f0eSIvan Vecera  * zl3073x_pin_check_freq - verify frequency for given pin
17a99a9f0eSIvan Vecera  * @zldev: pointer to zl3073x device
18a99a9f0eSIvan Vecera  * @dir: pin direction
19a99a9f0eSIvan Vecera  * @id: pin index
20a99a9f0eSIvan Vecera  * @freq: frequency to check
21a99a9f0eSIvan Vecera  *
22a99a9f0eSIvan Vecera  * The function checks the given frequency is valid for the device. For input
23a99a9f0eSIvan Vecera  * pins it checks that the frequency can be factorized using supported base
24a99a9f0eSIvan Vecera  * frequencies. For output pins it checks that the frequency divides connected
25a99a9f0eSIvan Vecera  * synth frequency without remainder.
26a99a9f0eSIvan Vecera  *
27a99a9f0eSIvan Vecera  * Return: true if the frequency is valid, false if not.
28a99a9f0eSIvan Vecera  */
29a99a9f0eSIvan Vecera static bool
30a99a9f0eSIvan Vecera zl3073x_pin_check_freq(struct zl3073x_dev *zldev, enum dpll_pin_direction dir,
31a99a9f0eSIvan Vecera 		       u8 id, u64 freq)
32a99a9f0eSIvan Vecera {
33a99a9f0eSIvan Vecera 	if (freq > U32_MAX)
34a99a9f0eSIvan Vecera 		goto err_inv_freq;
35a99a9f0eSIvan Vecera 
36a99a9f0eSIvan Vecera 	if (dir == DPLL_PIN_DIRECTION_INPUT) {
37a99a9f0eSIvan Vecera 		int rc;
38a99a9f0eSIvan Vecera 
39a99a9f0eSIvan Vecera 		/* Check if the frequency can be factorized */
40a99a9f0eSIvan Vecera 		rc = zl3073x_ref_freq_factorize(freq, NULL, NULL);
41a99a9f0eSIvan Vecera 		if (rc)
42a99a9f0eSIvan Vecera 			goto err_inv_freq;
43a99a9f0eSIvan Vecera 	} else {
44a99a9f0eSIvan Vecera 		u32 synth_freq;
45a99a9f0eSIvan Vecera 		u8 out, synth;
46a99a9f0eSIvan Vecera 
47a99a9f0eSIvan Vecera 		/* Get output pin synthesizer */
48a99a9f0eSIvan Vecera 		out = zl3073x_output_pin_out_get(id);
49a99a9f0eSIvan Vecera 		synth = zl3073x_out_synth_get(zldev, out);
50a99a9f0eSIvan Vecera 
51a99a9f0eSIvan Vecera 		/* Get synth frequency */
52a99a9f0eSIvan Vecera 		synth_freq = zl3073x_synth_freq_get(zldev, synth);
53a99a9f0eSIvan Vecera 
54a99a9f0eSIvan Vecera 		/* Check the frequency divides synth frequency */
55a99a9f0eSIvan Vecera 		if (synth_freq % (u32)freq)
56a99a9f0eSIvan Vecera 			goto err_inv_freq;
57a99a9f0eSIvan Vecera 	}
58a99a9f0eSIvan Vecera 
59a99a9f0eSIvan Vecera 	return true;
60a99a9f0eSIvan Vecera 
61a99a9f0eSIvan Vecera err_inv_freq:
62a99a9f0eSIvan Vecera 	dev_warn(zldev->dev,
63a99a9f0eSIvan Vecera 		 "Unsupported frequency %llu Hz in firmware node\n", freq);
64a99a9f0eSIvan Vecera 
65a99a9f0eSIvan Vecera 	return false;
66a99a9f0eSIvan Vecera }
67a99a9f0eSIvan Vecera 
68a99a9f0eSIvan Vecera /**
69a99a9f0eSIvan Vecera  * zl3073x_prop_pin_package_label_set - get package label for the pin
70a99a9f0eSIvan Vecera  * @zldev: pointer to zl3073x device
71a99a9f0eSIvan Vecera  * @props: pointer to pin properties
72a99a9f0eSIvan Vecera  * @dir: pin direction
73a99a9f0eSIvan Vecera  * @id: pin index
74a99a9f0eSIvan Vecera  *
75a99a9f0eSIvan Vecera  * Generates package label string and stores it into pin properties structure.
76a99a9f0eSIvan Vecera  *
77a99a9f0eSIvan Vecera  * Possible formats:
78a99a9f0eSIvan Vecera  * REF<n> - differential input reference
79a99a9f0eSIvan Vecera  * REF<n>P & REF<n>N - single-ended input reference (P or N pin)
80a99a9f0eSIvan Vecera  * OUT<n> - differential output
81a99a9f0eSIvan Vecera  * OUT<n>P & OUT<n>N - single-ended output (P or N pin)
82a99a9f0eSIvan Vecera  */
83a99a9f0eSIvan Vecera static void
84a99a9f0eSIvan Vecera zl3073x_prop_pin_package_label_set(struct zl3073x_dev *zldev,
85a99a9f0eSIvan Vecera 				   struct zl3073x_pin_props *props,
86a99a9f0eSIvan Vecera 				   enum dpll_pin_direction dir, u8 id)
87a99a9f0eSIvan Vecera {
88a99a9f0eSIvan Vecera 	const char *prefix, *suffix;
89a99a9f0eSIvan Vecera 	bool is_diff;
90a99a9f0eSIvan Vecera 
91a99a9f0eSIvan Vecera 	if (dir == DPLL_PIN_DIRECTION_INPUT) {
92a99a9f0eSIvan Vecera 		u8 ref;
93a99a9f0eSIvan Vecera 
94a99a9f0eSIvan Vecera 		prefix = "REF";
95a99a9f0eSIvan Vecera 		ref = zl3073x_input_pin_ref_get(id);
96a99a9f0eSIvan Vecera 		is_diff = zl3073x_ref_is_diff(zldev, ref);
97a99a9f0eSIvan Vecera 	} else {
98a99a9f0eSIvan Vecera 		u8 out;
99a99a9f0eSIvan Vecera 
100a99a9f0eSIvan Vecera 		prefix = "OUT";
101a99a9f0eSIvan Vecera 		out = zl3073x_output_pin_out_get(id);
102a99a9f0eSIvan Vecera 		is_diff = zl3073x_out_is_diff(zldev, out);
103a99a9f0eSIvan Vecera 	}
104a99a9f0eSIvan Vecera 
105a99a9f0eSIvan Vecera 	if (!is_diff)
106a99a9f0eSIvan Vecera 		suffix = zl3073x_is_p_pin(id) ? "P" : "N";
107a99a9f0eSIvan Vecera 	else
108a99a9f0eSIvan Vecera 		suffix = ""; /* No suffix for differential one */
109a99a9f0eSIvan Vecera 
110a99a9f0eSIvan Vecera 	snprintf(props->package_label, sizeof(props->package_label), "%s%u%s",
111a99a9f0eSIvan Vecera 		 prefix, id / 2, suffix);
112a99a9f0eSIvan Vecera 
113a99a9f0eSIvan Vecera 	/* Set package_label pointer in DPLL core properties to generated
114a99a9f0eSIvan Vecera 	 * string.
115a99a9f0eSIvan Vecera 	 */
116a99a9f0eSIvan Vecera 	props->dpll_props.package_label = props->package_label;
117a99a9f0eSIvan Vecera }
118a99a9f0eSIvan Vecera 
119a99a9f0eSIvan Vecera /**
120a99a9f0eSIvan Vecera  * zl3073x_prop_pin_fwnode_get - get fwnode for given pin
121a99a9f0eSIvan Vecera  * @zldev: pointer to zl3073x device
122a99a9f0eSIvan Vecera  * @props: pointer to pin properties
123a99a9f0eSIvan Vecera  * @dir: pin direction
124a99a9f0eSIvan Vecera  * @id: pin index
125a99a9f0eSIvan Vecera  *
126a99a9f0eSIvan Vecera  * Return: 0 on success, -ENOENT if the firmware node does not exist
127a99a9f0eSIvan Vecera  */
128a99a9f0eSIvan Vecera static int
129a99a9f0eSIvan Vecera zl3073x_prop_pin_fwnode_get(struct zl3073x_dev *zldev,
130a99a9f0eSIvan Vecera 			    struct zl3073x_pin_props *props,
131a99a9f0eSIvan Vecera 			    enum dpll_pin_direction dir, u8 id)
132a99a9f0eSIvan Vecera {
133a99a9f0eSIvan Vecera 	struct fwnode_handle *pins_node, *pin_node;
134a99a9f0eSIvan Vecera 	const char *node_name;
135a99a9f0eSIvan Vecera 
136a99a9f0eSIvan Vecera 	if (dir == DPLL_PIN_DIRECTION_INPUT)
137a99a9f0eSIvan Vecera 		node_name = "input-pins";
138a99a9f0eSIvan Vecera 	else
139a99a9f0eSIvan Vecera 		node_name = "output-pins";
140a99a9f0eSIvan Vecera 
141a99a9f0eSIvan Vecera 	/* Get node containing input or output pins */
142a99a9f0eSIvan Vecera 	pins_node = device_get_named_child_node(zldev->dev, node_name);
143a99a9f0eSIvan Vecera 	if (!pins_node) {
144a99a9f0eSIvan Vecera 		dev_dbg(zldev->dev, "'%s' sub-node is missing\n", node_name);
145a99a9f0eSIvan Vecera 		return -ENOENT;
146a99a9f0eSIvan Vecera 	}
147a99a9f0eSIvan Vecera 
148a99a9f0eSIvan Vecera 	/* Enumerate child pin nodes and find the requested one */
149a99a9f0eSIvan Vecera 	fwnode_for_each_child_node(pins_node, pin_node) {
150a99a9f0eSIvan Vecera 		u32 reg;
151a99a9f0eSIvan Vecera 
152a99a9f0eSIvan Vecera 		if (fwnode_property_read_u32(pin_node, "reg", &reg))
153a99a9f0eSIvan Vecera 			continue;
154a99a9f0eSIvan Vecera 
155a99a9f0eSIvan Vecera 		if (id == reg)
156a99a9f0eSIvan Vecera 			break;
157a99a9f0eSIvan Vecera 	}
158a99a9f0eSIvan Vecera 
159a99a9f0eSIvan Vecera 	/* Release pin parent node */
160a99a9f0eSIvan Vecera 	fwnode_handle_put(pins_node);
161a99a9f0eSIvan Vecera 
162a99a9f0eSIvan Vecera 	/* Save found node */
163a99a9f0eSIvan Vecera 	props->fwnode = pin_node;
164a99a9f0eSIvan Vecera 
165a99a9f0eSIvan Vecera 	dev_dbg(zldev->dev, "Firmware node for %s %sfound\n",
166a99a9f0eSIvan Vecera 		props->package_label, pin_node ? "" : "NOT ");
167a99a9f0eSIvan Vecera 
168a99a9f0eSIvan Vecera 	return pin_node ? 0 : -ENOENT;
169a99a9f0eSIvan Vecera }
170a99a9f0eSIvan Vecera 
171a99a9f0eSIvan Vecera /**
172a99a9f0eSIvan Vecera  * zl3073x_pin_props_get - get pin properties
173a99a9f0eSIvan Vecera  * @zldev: pointer to zl3073x device
174a99a9f0eSIvan Vecera  * @dir: pin direction
175a99a9f0eSIvan Vecera  * @index: pin index
176a99a9f0eSIvan Vecera  *
177a99a9f0eSIvan Vecera  * The function looks for firmware node for the given pin if it is provided
178a99a9f0eSIvan Vecera  * by the system firmware (DT or ACPI), allocates pin properties structure,
179a99a9f0eSIvan Vecera  * generates package label string according pin type and optionally fetches
180a99a9f0eSIvan Vecera  * board label, connection type, supported frequencies and esync capability
181a99a9f0eSIvan Vecera  * from the firmware node if it does exist.
182a99a9f0eSIvan Vecera  *
183a99a9f0eSIvan Vecera  * Pointer that is returned by this function should be freed using
184a99a9f0eSIvan Vecera  * @zl3073x_pin_props_put().
185a99a9f0eSIvan Vecera  *
186a99a9f0eSIvan Vecera  * Return:
187a99a9f0eSIvan Vecera  * * pointer to allocated pin properties structure on success
188a99a9f0eSIvan Vecera  * * error pointer in case of error
189a99a9f0eSIvan Vecera  */
190a99a9f0eSIvan Vecera struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
191a99a9f0eSIvan Vecera 						enum dpll_pin_direction dir,
192a99a9f0eSIvan Vecera 						u8 index)
193a99a9f0eSIvan Vecera {
194a99a9f0eSIvan Vecera 	struct dpll_pin_frequency *ranges;
195a99a9f0eSIvan Vecera 	struct zl3073x_pin_props *props;
196a99a9f0eSIvan Vecera 	int i, j, num_freqs, rc;
197a99a9f0eSIvan Vecera 	const char *type;
198a99a9f0eSIvan Vecera 	u64 *freqs;
199a99a9f0eSIvan Vecera 
200a99a9f0eSIvan Vecera 	props = kzalloc(sizeof(*props), GFP_KERNEL);
201a99a9f0eSIvan Vecera 	if (!props)
202a99a9f0eSIvan Vecera 		return ERR_PTR(-ENOMEM);
203a99a9f0eSIvan Vecera 
2049686c8b0SIvan Vecera 	/* Set default pin type and capabilities */
2059686c8b0SIvan Vecera 	if (dir == DPLL_PIN_DIRECTION_INPUT) {
206a99a9f0eSIvan Vecera 		props->dpll_props.type = DPLL_PIN_TYPE_EXT;
2079686c8b0SIvan Vecera 		props->dpll_props.capabilities =
208*12ba92f0SIvan Vecera 			DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
2099686c8b0SIvan Vecera 			DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
2109686c8b0SIvan Vecera 	} else {
211a99a9f0eSIvan Vecera 		props->dpll_props.type = DPLL_PIN_TYPE_GNSS;
2129686c8b0SIvan Vecera 	}
213a99a9f0eSIvan Vecera 
214a99a9f0eSIvan Vecera 	props->dpll_props.phase_range.min = S32_MIN;
215a99a9f0eSIvan Vecera 	props->dpll_props.phase_range.max = S32_MAX;
216a99a9f0eSIvan Vecera 
217a99a9f0eSIvan Vecera 	zl3073x_prop_pin_package_label_set(zldev, props, dir, index);
218a99a9f0eSIvan Vecera 
219a99a9f0eSIvan Vecera 	/* Get firmware node for the given pin */
220a99a9f0eSIvan Vecera 	rc = zl3073x_prop_pin_fwnode_get(zldev, props, dir, index);
221a99a9f0eSIvan Vecera 	if (rc)
222a99a9f0eSIvan Vecera 		return props; /* Return if it does not exist */
223a99a9f0eSIvan Vecera 
224a99a9f0eSIvan Vecera 	/* Look for label property and store the value as board label */
225a99a9f0eSIvan Vecera 	fwnode_property_read_string(props->fwnode, "label",
226a99a9f0eSIvan Vecera 				    &props->dpll_props.board_label);
227a99a9f0eSIvan Vecera 
228a99a9f0eSIvan Vecera 	/* Look for pin type property and translate its value to DPLL
229a99a9f0eSIvan Vecera 	 * pin type enum if it is present.
230a99a9f0eSIvan Vecera 	 */
231a99a9f0eSIvan Vecera 	if (!fwnode_property_read_string(props->fwnode, "connection-type",
232a99a9f0eSIvan Vecera 					 &type)) {
233a99a9f0eSIvan Vecera 		if (!strcmp(type, "ext"))
234a99a9f0eSIvan Vecera 			props->dpll_props.type = DPLL_PIN_TYPE_EXT;
235a99a9f0eSIvan Vecera 		else if (!strcmp(type, "gnss"))
236a99a9f0eSIvan Vecera 			props->dpll_props.type = DPLL_PIN_TYPE_GNSS;
237a99a9f0eSIvan Vecera 		else if (!strcmp(type, "int"))
238a99a9f0eSIvan Vecera 			props->dpll_props.type = DPLL_PIN_TYPE_INT_OSCILLATOR;
239a99a9f0eSIvan Vecera 		else if (!strcmp(type, "synce"))
240a99a9f0eSIvan Vecera 			props->dpll_props.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT;
241a99a9f0eSIvan Vecera 		else
242a99a9f0eSIvan Vecera 			dev_warn(zldev->dev,
243a99a9f0eSIvan Vecera 				 "Unknown or unsupported pin type '%s'\n",
244a99a9f0eSIvan Vecera 				 type);
245a99a9f0eSIvan Vecera 	}
246a99a9f0eSIvan Vecera 
247a99a9f0eSIvan Vecera 	/* Check if the pin supports embedded sync control */
248a99a9f0eSIvan Vecera 	props->esync_control = fwnode_property_read_bool(props->fwnode,
249a99a9f0eSIvan Vecera 							 "esync-control");
250a99a9f0eSIvan Vecera 
251a99a9f0eSIvan Vecera 	/* Read supported frequencies property if it is specified */
252a99a9f0eSIvan Vecera 	num_freqs = fwnode_property_count_u64(props->fwnode,
253a99a9f0eSIvan Vecera 					      "supported-frequencies-hz");
254a99a9f0eSIvan Vecera 	if (num_freqs <= 0)
255a99a9f0eSIvan Vecera 		/* Return if the property does not exist or number is 0 */
256a99a9f0eSIvan Vecera 		return props;
257a99a9f0eSIvan Vecera 
258a99a9f0eSIvan Vecera 	/* The firmware node specifies list of supported frequencies while
259a99a9f0eSIvan Vecera 	 * DPLL core pin properties requires list of frequency ranges.
260a99a9f0eSIvan Vecera 	 * So read the frequency list into temporary array.
261a99a9f0eSIvan Vecera 	 */
262a99a9f0eSIvan Vecera 	freqs = kcalloc(num_freqs, sizeof(*freqs), GFP_KERNEL);
263a99a9f0eSIvan Vecera 	if (!freqs) {
264a99a9f0eSIvan Vecera 		rc = -ENOMEM;
265a99a9f0eSIvan Vecera 		goto err_alloc_freqs;
266a99a9f0eSIvan Vecera 	}
267a99a9f0eSIvan Vecera 
268a99a9f0eSIvan Vecera 	/* Read frequencies list from firmware node */
269a99a9f0eSIvan Vecera 	fwnode_property_read_u64_array(props->fwnode,
270a99a9f0eSIvan Vecera 				       "supported-frequencies-hz", freqs,
271a99a9f0eSIvan Vecera 				       num_freqs);
272a99a9f0eSIvan Vecera 
273a99a9f0eSIvan Vecera 	/* Allocate frequency ranges list and fill it */
274a99a9f0eSIvan Vecera 	ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL);
275a99a9f0eSIvan Vecera 	if (!ranges) {
276a99a9f0eSIvan Vecera 		rc = -ENOMEM;
277a99a9f0eSIvan Vecera 		goto err_alloc_ranges;
278a99a9f0eSIvan Vecera 	}
279a99a9f0eSIvan Vecera 
280a99a9f0eSIvan Vecera 	/* Convert list of frequencies to list of frequency ranges but
281a99a9f0eSIvan Vecera 	 * filter-out frequencies that are not representable by device
282a99a9f0eSIvan Vecera 	 */
283a99a9f0eSIvan Vecera 	for (i = 0, j = 0; i < num_freqs; i++) {
284a99a9f0eSIvan Vecera 		struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]);
285a99a9f0eSIvan Vecera 
286a99a9f0eSIvan Vecera 		if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) {
287a99a9f0eSIvan Vecera 			ranges[j] = freq;
288a99a9f0eSIvan Vecera 			j++;
289a99a9f0eSIvan Vecera 		}
290a99a9f0eSIvan Vecera 	}
291a99a9f0eSIvan Vecera 
292a99a9f0eSIvan Vecera 	/* Save number of freq ranges and pointer to them into pin properties */
293a99a9f0eSIvan Vecera 	props->dpll_props.freq_supported = ranges;
294a99a9f0eSIvan Vecera 	props->dpll_props.freq_supported_num = j;
295a99a9f0eSIvan Vecera 
296a99a9f0eSIvan Vecera 	/* Free temporary array */
297a99a9f0eSIvan Vecera 	kfree(freqs);
298a99a9f0eSIvan Vecera 
299a99a9f0eSIvan Vecera 	return props;
300a99a9f0eSIvan Vecera 
301a99a9f0eSIvan Vecera err_alloc_ranges:
302a99a9f0eSIvan Vecera 	kfree(freqs);
303a99a9f0eSIvan Vecera err_alloc_freqs:
304a99a9f0eSIvan Vecera 	fwnode_handle_put(props->fwnode);
305a99a9f0eSIvan Vecera 	kfree(props);
306a99a9f0eSIvan Vecera 
307a99a9f0eSIvan Vecera 	return ERR_PTR(rc);
308a99a9f0eSIvan Vecera }
309a99a9f0eSIvan Vecera 
310a99a9f0eSIvan Vecera /**
311a99a9f0eSIvan Vecera  * zl3073x_pin_props_put - release pin properties
312a99a9f0eSIvan Vecera  * @props: pin properties to free
313a99a9f0eSIvan Vecera  *
314a99a9f0eSIvan Vecera  * The function deallocates given pin properties structure.
315a99a9f0eSIvan Vecera  */
316a99a9f0eSIvan Vecera void zl3073x_pin_props_put(struct zl3073x_pin_props *props)
317a99a9f0eSIvan Vecera {
318a99a9f0eSIvan Vecera 	/* Free supported frequency ranges list if it is present */
319a99a9f0eSIvan Vecera 	kfree(props->dpll_props.freq_supported);
320a99a9f0eSIvan Vecera 
321a99a9f0eSIvan Vecera 	/* Put firmware handle if it is present */
322a99a9f0eSIvan Vecera 	if (props->fwnode)
323a99a9f0eSIvan Vecera 		fwnode_handle_put(props->fwnode);
324a99a9f0eSIvan Vecera 
325a99a9f0eSIvan Vecera 	kfree(props);
326a99a9f0eSIvan Vecera }
327a99a9f0eSIvan Vecera 
328a99a9f0eSIvan Vecera /**
329a99a9f0eSIvan Vecera  * zl3073x_prop_dpll_type_get - get DPLL channel type
330a99a9f0eSIvan Vecera  * @zldev: pointer to zl3073x device
331a99a9f0eSIvan Vecera  * @index: DPLL channel index
332a99a9f0eSIvan Vecera  *
333a99a9f0eSIvan Vecera  * Return: DPLL type for given DPLL channel
334a99a9f0eSIvan Vecera  */
335a99a9f0eSIvan Vecera enum dpll_type
336a99a9f0eSIvan Vecera zl3073x_prop_dpll_type_get(struct zl3073x_dev *zldev, u8 index)
337a99a9f0eSIvan Vecera {
338a99a9f0eSIvan Vecera 	const char *types[ZL3073X_MAX_CHANNELS];
339a99a9f0eSIvan Vecera 	int count;
340a99a9f0eSIvan Vecera 
341a99a9f0eSIvan Vecera 	/* Read dpll types property from firmware */
342a99a9f0eSIvan Vecera 	count = device_property_read_string_array(zldev->dev, "dpll-types",
343a99a9f0eSIvan Vecera 						  types, ARRAY_SIZE(types));
344a99a9f0eSIvan Vecera 
345a99a9f0eSIvan Vecera 	/* Return default if property or entry for given channel is missing */
346a99a9f0eSIvan Vecera 	if (index >= count)
347a99a9f0eSIvan Vecera 		return DPLL_TYPE_PPS;
348a99a9f0eSIvan Vecera 
349a99a9f0eSIvan Vecera 	if (!strcmp(types[index], "pps"))
350a99a9f0eSIvan Vecera 		return DPLL_TYPE_PPS;
351a99a9f0eSIvan Vecera 	else if (!strcmp(types[index], "eec"))
352a99a9f0eSIvan Vecera 		return DPLL_TYPE_EEC;
353a99a9f0eSIvan Vecera 
354a99a9f0eSIvan Vecera 	dev_info(zldev->dev, "Unknown DPLL type '%s', using default\n",
355a99a9f0eSIvan Vecera 		 types[index]);
356a99a9f0eSIvan Vecera 
357a99a9f0eSIvan Vecera 	return DPLL_TYPE_PPS; /* Default */
358a99a9f0eSIvan Vecera }
359