Merge branch 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux into drm...
[linux-2.6-microblaze.git] / drivers / usb / typec / pd.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * USB Power Delivery sysfs entries
4  *
5  * Copyright (C) 2022, Intel Corporation
6  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
7  */
8
9 #include <linux/slab.h>
10 #include <linux/usb/pd.h>
11
12 #include "pd.h"
13
14 static DEFINE_IDA(pd_ida);
15
16 static struct class pd_class = {
17         .name = "usb_power_delivery",
18         .owner = THIS_MODULE,
19 };
20
21 #define to_pdo(o) container_of(o, struct pdo, dev)
22
23 struct pdo {
24         struct device dev;
25         int object_position;
26         u32 pdo;
27 };
28
29 static void pdo_release(struct device *dev)
30 {
31         kfree(to_pdo(dev));
32 }
33
34 /* -------------------------------------------------------------------------- */
35 /* Fixed Supply */
36
37 static ssize_t
38 dual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf)
39 {
40         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE));
41 }
42 static DEVICE_ATTR_RO(dual_role_power);
43
44 static ssize_t
45 usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf)
46 {
47         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND));
48 }
49 static DEVICE_ATTR_RO(usb_suspend_supported);
50
51 static ssize_t
52 unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf)
53 {
54         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER));
55 }
56 static DEVICE_ATTR_RO(unconstrained_power);
57
58 static ssize_t
59 usb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf)
60 {
61         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM));
62 }
63 static DEVICE_ATTR_RO(usb_communication_capable);
64
65 static ssize_t
66 dual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf)
67 {
68         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP));
69 }
70 static DEVICE_ATTR_RO(dual_role_data);
71
72 static ssize_t
73 unchunked_extended_messages_supported_show(struct device *dev,
74                                            struct device_attribute *attr, char *buf)
75 {
76         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT));
77 }
78 static DEVICE_ATTR_RO(unchunked_extended_messages_supported);
79
80 /*
81  * REVISIT: Peak Current requires access also to the RDO.
82 static ssize_t
83 peak_current_show(struct device *dev, struct device_attribute *attr, char *buf)
84 {
85         ...
86 }
87 */
88
89 static ssize_t
90 fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf)
91 {
92         return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3;
93 }
94 static DEVICE_ATTR_RO(fast_role_swap_current);
95
96 static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
97 {
98         return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo));
99 }
100 static DEVICE_ATTR_RO(voltage);
101
102 /* Shared with Variable supplies, both source and sink */
103 static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf)
104 {
105         return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo));
106 }
107
108 /* Shared with Variable type supplies */
109 static struct device_attribute maximum_current_attr = {
110         .attr = {
111                 .name = "maximum_current",
112                 .mode = 0444,
113         },
114         .show = current_show,
115 };
116
117 static struct device_attribute operational_current_attr = {
118         .attr = {
119                 .name = "operational_current",
120                 .mode = 0444,
121         },
122         .show = current_show,
123 };
124
125 static struct attribute *source_fixed_supply_attrs[] = {
126         &dev_attr_dual_role_power.attr,
127         &dev_attr_usb_suspend_supported.attr,
128         &dev_attr_unconstrained_power.attr,
129         &dev_attr_usb_communication_capable.attr,
130         &dev_attr_dual_role_data.attr,
131         &dev_attr_unchunked_extended_messages_supported.attr,
132         /*&dev_attr_peak_current.attr,*/
133         &dev_attr_voltage.attr,
134         &maximum_current_attr.attr,
135         NULL
136 };
137
138 static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
139 {
140         if (to_pdo(kobj_to_dev(kobj))->object_position &&
141             /*attr != &dev_attr_peak_current.attr &&*/
142             attr != &dev_attr_voltage.attr &&
143             attr != &maximum_current_attr.attr &&
144             attr != &operational_current_attr.attr)
145                 return 0;
146
147         return attr->mode;
148 }
149
150 static const struct attribute_group source_fixed_supply_group = {
151         .is_visible = fixed_attr_is_visible,
152         .attrs = source_fixed_supply_attrs,
153 };
154 __ATTRIBUTE_GROUPS(source_fixed_supply);
155
156 static struct device_type source_fixed_supply_type = {
157         .name = "pdo",
158         .release = pdo_release,
159         .groups = source_fixed_supply_groups,
160 };
161
162 static struct attribute *sink_fixed_supply_attrs[] = {
163         &dev_attr_dual_role_power.attr,
164         &dev_attr_usb_suspend_supported.attr,
165         &dev_attr_unconstrained_power.attr,
166         &dev_attr_usb_communication_capable.attr,
167         &dev_attr_dual_role_data.attr,
168         &dev_attr_unchunked_extended_messages_supported.attr,
169         &dev_attr_fast_role_swap_current.attr,
170         &dev_attr_voltage.attr,
171         &operational_current_attr.attr,
172         NULL
173 };
174
175 static const struct attribute_group sink_fixed_supply_group = {
176         .is_visible = fixed_attr_is_visible,
177         .attrs = sink_fixed_supply_attrs,
178 };
179 __ATTRIBUTE_GROUPS(sink_fixed_supply);
180
181 static struct device_type sink_fixed_supply_type = {
182         .name = "pdo",
183         .release = pdo_release,
184         .groups = sink_fixed_supply_groups,
185 };
186
187 /* -------------------------------------------------------------------------- */
188 /* Variable Supply */
189
190 static ssize_t
191 maximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
192 {
193         return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo));
194 }
195 static DEVICE_ATTR_RO(maximum_voltage);
196
197 static ssize_t
198 minimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
199 {
200         return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo));
201 }
202 static DEVICE_ATTR_RO(minimum_voltage);
203
204 static struct attribute *source_variable_supply_attrs[] = {
205         &dev_attr_maximum_voltage.attr,
206         &dev_attr_minimum_voltage.attr,
207         &maximum_current_attr.attr,
208         NULL
209 };
210 ATTRIBUTE_GROUPS(source_variable_supply);
211
212 static struct device_type source_variable_supply_type = {
213         .name = "pdo",
214         .release = pdo_release,
215         .groups = source_variable_supply_groups,
216 };
217
218 static struct attribute *sink_variable_supply_attrs[] = {
219         &dev_attr_maximum_voltage.attr,
220         &dev_attr_minimum_voltage.attr,
221         &operational_current_attr.attr,
222         NULL
223 };
224 ATTRIBUTE_GROUPS(sink_variable_supply);
225
226 static struct device_type sink_variable_supply_type = {
227         .name = "pdo",
228         .release = pdo_release,
229         .groups = sink_variable_supply_groups,
230 };
231
232 /* -------------------------------------------------------------------------- */
233 /* Battery */
234
235 static ssize_t
236 maximum_power_show(struct device *dev, struct device_attribute *attr, char *buf)
237 {
238         return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo));
239 }
240 static DEVICE_ATTR_RO(maximum_power);
241
242 static ssize_t
243 operational_power_show(struct device *dev, struct device_attribute *attr, char *buf)
244 {
245         return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo));
246 }
247 static DEVICE_ATTR_RO(operational_power);
248
249 static struct attribute *source_battery_attrs[] = {
250         &dev_attr_maximum_voltage.attr,
251         &dev_attr_minimum_voltage.attr,
252         &dev_attr_maximum_power.attr,
253         NULL
254 };
255 ATTRIBUTE_GROUPS(source_battery);
256
257 static struct device_type source_battery_type = {
258         .name = "pdo",
259         .release = pdo_release,
260         .groups = source_battery_groups,
261 };
262
263 static struct attribute *sink_battery_attrs[] = {
264         &dev_attr_maximum_voltage.attr,
265         &dev_attr_minimum_voltage.attr,
266         &dev_attr_operational_power.attr,
267         NULL
268 };
269 ATTRIBUTE_GROUPS(sink_battery);
270
271 static struct device_type sink_battery_type = {
272         .name = "pdo",
273         .release = pdo_release,
274         .groups = sink_battery_groups,
275 };
276
277 /* -------------------------------------------------------------------------- */
278 /* Standard Power Range (SPR) Programmable Power Supply (PPS) */
279
280 static ssize_t
281 pps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf)
282 {
283         return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27)));
284 }
285 static DEVICE_ATTR_RO(pps_power_limited);
286
287 static ssize_t
288 pps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
289 {
290         return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo));
291 }
292
293 static ssize_t
294 pps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
295 {
296         return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo));
297 }
298
299 static ssize_t
300 pps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf)
301 {
302         return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo));
303 }
304
305 static struct device_attribute pps_max_voltage_attr = {
306         .attr = {
307                 .name = "maximum_voltage",
308                 .mode = 0444,
309         },
310         .show = pps_max_voltage_show,
311 };
312
313 static struct device_attribute pps_min_voltage_attr = {
314         .attr = {
315                 .name = "minimum_voltage",
316                 .mode = 0444,
317         },
318         .show = pps_min_voltage_show,
319 };
320
321 static struct device_attribute pps_max_current_attr = {
322         .attr = {
323                 .name = "maximum_current",
324                 .mode = 0444,
325         },
326         .show = pps_max_current_show,
327 };
328
329 static struct attribute *source_pps_attrs[] = {
330         &dev_attr_pps_power_limited.attr,
331         &pps_max_voltage_attr.attr,
332         &pps_min_voltage_attr.attr,
333         &pps_max_current_attr.attr,
334         NULL
335 };
336 ATTRIBUTE_GROUPS(source_pps);
337
338 static struct device_type source_pps_type = {
339         .name = "pdo",
340         .release = pdo_release,
341         .groups = source_pps_groups,
342 };
343
344 static struct attribute *sink_pps_attrs[] = {
345         &pps_max_voltage_attr.attr,
346         &pps_min_voltage_attr.attr,
347         &pps_max_current_attr.attr,
348         NULL
349 };
350 ATTRIBUTE_GROUPS(sink_pps);
351
352 static struct device_type sink_pps_type = {
353         .name = "pdo",
354         .release = pdo_release,
355         .groups = sink_pps_groups,
356 };
357
358 /* -------------------------------------------------------------------------- */
359
360 static const char * const supply_name[] = {
361         [PDO_TYPE_FIXED] = "fixed_supply",
362         [PDO_TYPE_BATT]  = "battery",
363         [PDO_TYPE_VAR]   = "variable_supply",
364 };
365
366 static const char * const apdo_supply_name[] = {
367         [APDO_TYPE_PPS]  = "programmable_supply",
368 };
369
370 static struct device_type *source_type[] = {
371         [PDO_TYPE_FIXED] = &source_fixed_supply_type,
372         [PDO_TYPE_BATT]  = &source_battery_type,
373         [PDO_TYPE_VAR]   = &source_variable_supply_type,
374 };
375
376 static struct device_type *source_apdo_type[] = {
377         [APDO_TYPE_PPS]  = &source_pps_type,
378 };
379
380 static struct device_type *sink_type[] = {
381         [PDO_TYPE_FIXED] = &sink_fixed_supply_type,
382         [PDO_TYPE_BATT]  = &sink_battery_type,
383         [PDO_TYPE_VAR]   = &sink_variable_supply_type,
384 };
385
386 static struct device_type *sink_apdo_type[] = {
387         [APDO_TYPE_PPS]  = &sink_pps_type,
388 };
389
390 /* REVISIT: Export when EPR_*_Capabilities need to be supported. */
391 static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position)
392 {
393         struct device_type *type;
394         const char *name;
395         struct pdo *p;
396         int ret;
397
398         p = kzalloc(sizeof(*p), GFP_KERNEL);
399         if (!p)
400                 return -ENOMEM;
401
402         p->pdo = pdo;
403         p->object_position = position;
404
405         if (pdo_type(pdo) == PDO_TYPE_APDO) {
406                 /* FIXME: Only PPS supported for now! Skipping others. */
407                 if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) {
408                         dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo);
409                         kfree(p);
410                         return 0;
411                 }
412
413                 if (is_source(cap->role))
414                         type = source_apdo_type[pdo_apdo_type(pdo)];
415                 else
416                         type = sink_apdo_type[pdo_apdo_type(pdo)];
417
418                 name = apdo_supply_name[pdo_apdo_type(pdo)];
419         } else {
420                 if (is_source(cap->role))
421                         type = source_type[pdo_type(pdo)];
422                 else
423                         type = sink_type[pdo_type(pdo)];
424
425                 name = supply_name[pdo_type(pdo)];
426         }
427
428         p->dev.parent = &cap->dev;
429         p->dev.type = type;
430         dev_set_name(&p->dev, "%u:%s", position + 1, name);
431
432         ret = device_register(&p->dev);
433         if (ret) {
434                 put_device(&p->dev);
435                 return ret;
436         }
437
438         return 0;
439 }
440
441 static int remove_pdo(struct device *dev, void *data)
442 {
443         device_unregister(dev);
444         return 0;
445 }
446
447 /* -------------------------------------------------------------------------- */
448
449 static const char * const cap_name[] = {
450         [TYPEC_SINK]    = "sink-capabilities",
451         [TYPEC_SOURCE]  = "source-capabilities",
452 };
453
454 static void pd_capabilities_release(struct device *dev)
455 {
456         kfree(to_usb_power_delivery_capabilities(dev));
457 }
458
459 static struct device_type pd_capabilities_type = {
460         .name = "capabilities",
461         .release = pd_capabilities_release,
462 };
463
464 /**
465  * usb_power_delivery_register_capabilities - Register a set of capabilities.
466  * @pd: The USB PD instance that the capabilities belong to.
467  * @desc: Description of the Capablities Message.
468  *
469  * This function registers a Capabilities Message described in @desc. The
470  * capabilities will have their own sub-directory under @pd in sysfs.
471  *
472  * The function returns pointer to struct usb_power_delivery_capabilities, or
473  * ERR_PRT(errno).
474  */
475 struct usb_power_delivery_capabilities *
476 usb_power_delivery_register_capabilities(struct usb_power_delivery *pd,
477                                          struct usb_power_delivery_capabilities_desc *desc)
478 {
479         struct usb_power_delivery_capabilities *cap;
480         int ret;
481         int i;
482
483         cap = kzalloc(sizeof(*cap), GFP_KERNEL);
484         if (!cap)
485                 return ERR_PTR(-ENOMEM);
486
487         cap->pd = pd;
488         cap->role = desc->role;
489
490         cap->dev.parent = &pd->dev;
491         cap->dev.type = &pd_capabilities_type;
492         dev_set_name(&cap->dev, "%s", cap_name[cap->role]);
493
494         ret = device_register(&cap->dev);
495         if (ret) {
496                 put_device(&cap->dev);
497                 return ERR_PTR(ret);
498         }
499
500         for (i = 0; i < PDO_MAX_OBJECTS && desc->pdo[i]; i++) {
501                 ret = add_pdo(cap, desc->pdo[i], i);
502                 if (ret) {
503                         usb_power_delivery_unregister_capabilities(cap);
504                         return ERR_PTR(ret);
505                 }
506         }
507
508         return cap;
509 }
510 EXPORT_SYMBOL_GPL(usb_power_delivery_register_capabilities);
511
512 /**
513  * usb_power_delivery_unregister_capabilities - Unregister a set of capabilities
514  * @cap: The capabilities
515  */
516 void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap)
517 {
518         if (!cap)
519                 return;
520
521         device_for_each_child(&cap->dev, NULL, remove_pdo);
522         device_unregister(&cap->dev);
523 }
524 EXPORT_SYMBOL_GPL(usb_power_delivery_unregister_capabilities);
525
526 /* -------------------------------------------------------------------------- */
527
528 static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf)
529 {
530         struct usb_power_delivery *pd = to_usb_power_delivery(dev);
531
532         return sysfs_emit(buf, "%u.%u\n", (pd->revision >> 8) & 0xff, (pd->revision >> 4) & 0xf);
533 }
534 static DEVICE_ATTR_RO(revision);
535
536 static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
537 {
538         struct usb_power_delivery *pd = to_usb_power_delivery(dev);
539
540         return sysfs_emit(buf, "%u.%u\n", (pd->version >> 8) & 0xff, (pd->version >> 4) & 0xf);
541 }
542 static DEVICE_ATTR_RO(version);
543
544 static struct attribute *pd_attrs[] = {
545         &dev_attr_revision.attr,
546         &dev_attr_version.attr,
547         NULL
548 };
549
550 static umode_t pd_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
551 {
552         struct usb_power_delivery *pd = to_usb_power_delivery(kobj_to_dev(kobj));
553
554         if (attr == &dev_attr_version.attr && !pd->version)
555                 return 0;
556
557         return attr->mode;
558 }
559
560 static const struct attribute_group pd_group = {
561         .is_visible = pd_attr_is_visible,
562         .attrs = pd_attrs,
563 };
564 __ATTRIBUTE_GROUPS(pd);
565
566 static void pd_release(struct device *dev)
567 {
568         struct usb_power_delivery *pd = to_usb_power_delivery(dev);
569
570         ida_simple_remove(&pd_ida, pd->id);
571         kfree(pd);
572 }
573
574 static struct device_type pd_type = {
575         .name = "usb_power_delivery",
576         .release = pd_release,
577         .groups = pd_groups,
578 };
579
580 struct usb_power_delivery *usb_power_delivery_find(const char *name)
581 {
582         struct device *dev;
583
584         dev = class_find_device_by_name(&pd_class, name);
585
586         return dev ? to_usb_power_delivery(dev) : NULL;
587 }
588
589 /**
590  * usb_power_delivery_register - Register USB Power Delivery Support.
591  * @parent: Parent device.
592  * @desc: Description of the USB PD contract.
593  *
594  * This routine can be used to register USB Power Delivery capabilities that a
595  * device or devices can support. These capabilities represent all the
596  * capabilities that can be negotiated with a partner, so not only the Power
597  * Capabilities that are negotiated using the USB PD Capabilities Message.
598  *
599  * The USB Power Delivery Support object that this routine generates can be used
600  * as the parent object for all the actual USB Power Delivery Messages and
601  * objects that can be negotiated with the partner.
602  *
603  * Returns handle to struct usb_power_delivery or ERR_PTR.
604  */
605 struct usb_power_delivery *
606 usb_power_delivery_register(struct device *parent, struct usb_power_delivery_desc *desc)
607 {
608         struct usb_power_delivery *pd;
609         int ret;
610
611         pd = kzalloc(sizeof(*pd), GFP_KERNEL);
612         if (!pd)
613                 return ERR_PTR(-ENOMEM);
614
615         ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL);
616         if (ret < 0) {
617                 kfree(pd);
618                 return ERR_PTR(ret);
619         }
620
621         pd->id = ret;
622         pd->revision = desc->revision;
623         pd->version = desc->version;
624
625         pd->dev.parent = parent;
626         pd->dev.type = &pd_type;
627         pd->dev.class = &pd_class;
628         dev_set_name(&pd->dev, "pd%d", pd->id);
629
630         ret = device_register(&pd->dev);
631         if (ret) {
632                 put_device(&pd->dev);
633                 return ERR_PTR(ret);
634         }
635
636         return pd;
637 }
638 EXPORT_SYMBOL_GPL(usb_power_delivery_register);
639
640 /**
641  * usb_power_delivery_unregister - Unregister USB Power Delivery Support.
642  * @pd: The USB PD contract.
643  */
644 void usb_power_delivery_unregister(struct usb_power_delivery *pd)
645 {
646         if (IS_ERR_OR_NULL(pd))
647                 return;
648
649         device_unregister(&pd->dev);
650 }
651 EXPORT_SYMBOL_GPL(usb_power_delivery_unregister);
652
653 /**
654  * usb_power_delivery_link_device - Link device to its USB PD object.
655  * @pd: The USB PD instance.
656  * @dev: The device.
657  *
658  * This function can be used to create a symlink named "usb_power_delivery" for
659  * @dev that points to @pd.
660  */
661 int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev)
662 {
663         int ret;
664
665         if (IS_ERR_OR_NULL(pd) || !dev)
666                 return 0;
667
668         ret = sysfs_create_link(&dev->kobj, &pd->dev.kobj, "usb_power_delivery");
669         if (ret)
670                 return ret;
671
672         get_device(&pd->dev);
673         get_device(dev);
674
675         return 0;
676 }
677 EXPORT_SYMBOL_GPL(usb_power_delivery_link_device);
678
679 /**
680  * usb_power_delivery_unlink_device - Unlink device from its USB PD object.
681  * @pd: The USB PD instance.
682  * @dev: The device.
683  *
684  * Remove the symlink that was previously created with pd_link_device().
685  */
686 void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev)
687 {
688         if (IS_ERR_OR_NULL(pd) || !dev)
689                 return;
690
691         sysfs_remove_link(&dev->kobj, "usb_power_delivery");
692         put_device(&pd->dev);
693         put_device(dev);
694 }
695 EXPORT_SYMBOL_GPL(usb_power_delivery_unlink_device);
696
697 /* -------------------------------------------------------------------------- */
698
699 int __init usb_power_delivery_init(void)
700 {
701         return class_register(&pd_class);
702 }
703
704 void __exit usb_power_delivery_exit(void)
705 {
706         ida_destroy(&pd_ida);
707         class_unregister(&pd_class);
708 }