| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- .. SPDX-License-Identifier: GPL-2.0
- ===============================
- The Linux kernel dpll subsystem
- ===============================
- DPLL
- ====
- PLL - Phase Locked Loop is an electronic circuit which syntonizes clock
- signal of a device with an external clock signal. Effectively enabling
- device to run on the same clock signal beat as provided on a PLL input.
- DPLL - Digital Phase Locked Loop is an integrated circuit which in
- addition to plain PLL behavior incorporates a digital phase detector
- and may have digital divider in the loop. As a result, the frequency on
- DPLL's input and output may be configurable.
- Subsystem
- =========
- The main purpose of dpll subsystem is to provide general interface
- to configure devices that use any kind of Digital PLL and could use
- different sources of input signal to synchronize to, as well as
- different types of outputs.
- The main interface is NETLINK_GENERIC based protocol with an event
- monitoring multicast group defined.
- Device object
- =============
- Single dpll device object means single Digital PLL circuit and bunch of
- connected pins.
- It reports the supported modes of operation and current status to the
- user in response to the `do` request of netlink command
- ``DPLL_CMD_DEVICE_GET`` and list of dplls registered in the subsystem
- with `dump` netlink request of the same command.
- Changing the configuration of dpll device is done with `do` request of
- netlink ``DPLL_CMD_DEVICE_SET`` command.
- A device handle is ``DPLL_A_ID``, it shall be provided to get or set
- configuration of particular device in the system. It can be obtained
- with a ``DPLL_CMD_DEVICE_GET`` `dump` request or
- a ``DPLL_CMD_DEVICE_ID_GET`` `do` request, where the one must provide
- attributes that result in single device match.
- Pin object
- ==========
- A pin is amorphic object which represents either input or output, it
- could be internal component of the device, as well as externally
- connected.
- The number of pins per dpll vary, but usually multiple pins shall be
- provided for a single dpll device.
- Pin's properties, capabilities and status is provided to the user in
- response to `do` request of netlink ``DPLL_CMD_PIN_GET`` command.
- It is also possible to list all the pins that were registered in the
- system with `dump` request of ``DPLL_CMD_PIN_GET`` command.
- Configuration of a pin can be changed by `do` request of netlink
- ``DPLL_CMD_PIN_SET`` command.
- Pin handle is a ``DPLL_A_PIN_ID``, it shall be provided to get or set
- configuration of particular pin in the system. It can be obtained with
- ``DPLL_CMD_PIN_GET`` `dump` request or ``DPLL_CMD_PIN_ID_GET`` `do`
- request, where user provides attributes that result in single pin match.
- Pin selection
- =============
- In general, selected pin (the one which signal is driving the dpll
- device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only
- one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll
- device.
- Pin selection can be done either manually or automatically, depending
- on hardware capabilities and active dpll device work mode
- (``DPLL_A_MODE`` attribute). The consequence is that there are
- differences for each mode in terms of available pin states, as well as
- for the states the user can request for a dpll device.
- In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive
- one of following pin states:
- - ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device
- - ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll
- device
- In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or
- receive one of following pin states:
- - ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid
- input for automatic selection algorithm
- - ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as
- a valid input for automatic selection algorithm
- In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive
- pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection
- algorithm locks a dpll device with one of the inputs.
- Shared pins
- ===========
- A single pin object can be attached to multiple dpll devices.
- Then there are two groups of configuration knobs:
- 1) Set on a pin - the configuration affects all dpll devices pin is
- registered to (i.e., ``DPLL_A_PIN_FREQUENCY``),
- 2) Set on a pin-dpll tuple - the configuration affects only selected
- dpll device (i.e., ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE``,
- ``DPLL_A_PIN_DIRECTION``).
- MUX-type pins
- =============
- A pin can be MUX-type, it aggregates child pins and serves as a pin
- multiplexer. One or more pins are registered with MUX-type instead of
- being directly registered to a dpll device.
- Pins registered with a MUX-type pin provide user with additional nested
- attribute ``DPLL_A_PIN_PARENT_PIN`` for each parent they were registered
- with.
- If a pin was registered with multiple parent pins, they behave like a
- multiple output multiplexer. In this case output of a
- ``DPLL_CMD_PIN_GET`` would contain multiple pin-parent nested
- attributes with current state related to each parent, like::
- 'pin': [{{
- 'clock-id': 282574471561216,
- 'module-name': 'ice',
- 'capabilities': 4,
- 'id': 13,
- 'parent-pin': [
- {'parent-id': 2, 'state': 'connected'},
- {'parent-id': 3, 'state': 'disconnected'}
- ],
- 'type': 'synce-eth-port'
- }}]
- Only one child pin can provide its signal to the parent MUX-type pin at
- a time, the selection is done by requesting change of a child pin state
- on desired parent, with the use of ``DPLL_A_PIN_PARENT`` nested
- attribute. Example of netlink `set state on parent pin` message format:
- ========================== =============================================
- ``DPLL_A_PIN_ID`` child pin id
- ``DPLL_A_PIN_PARENT_PIN`` nested attribute for requesting configuration
- related to parent pin
- ``DPLL_A_PIN_PARENT_ID`` parent pin id
- ``DPLL_A_PIN_STATE`` requested pin state on parent
- ========================== =============================================
- Pin priority
- ============
- Some devices might offer a capability of automatic pin selection mode
- (enum value ``DPLL_MODE_AUTOMATIC`` of ``DPLL_A_MODE`` attribute).
- Usually, automatic selection is performed on the hardware level, which
- means only pins directly connected to the dpll can be used for automatic
- input pin selection.
- In automatic selection mode, the user cannot manually select a input
- pin for the device, instead the user shall provide all directly
- connected pins with a priority ``DPLL_A_PIN_PRIO``, the device would
- pick a highest priority valid signal and use it to control the DPLL
- device. Example of netlink `set priority on parent pin` message format:
- ============================ =============================================
- ``DPLL_A_PIN_ID`` configured pin id
- ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting configuration
- related to parent dpll device
- ``DPLL_A_PIN_PARENT_ID`` parent dpll device id
- ``DPLL_A_PIN_PRIO`` requested pin prio on parent dpll
- ============================ =============================================
- Child pin of MUX-type pin is not capable of automatic input pin selection,
- in order to configure active input of a MUX-type pin, the user needs to
- request desired pin state of the child pin on the parent pin,
- as described in the ``MUX-type pins`` chapter.
- Phase offset measurement and adjustment
- ========================================
- Device may provide ability to measure a phase difference between signals
- on a pin and its parent dpll device. If pin-dpll phase offset measurement
- is supported, it shall be provided with ``DPLL_A_PIN_PHASE_OFFSET``
- attribute for each parent dpll device.
- Device may also provide ability to adjust a signal phase on a pin.
- If pin phase adjustment is supported, minimal and maximal values that pin
- handle shall be provide to the user on ``DPLL_CMD_PIN_GET`` respond
- with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and ``DPLL_A_PIN_PHASE_ADJUST_MAX``
- attributes. Configured phase adjust value is provided with
- ``DPLL_A_PIN_PHASE_ADJUST`` attribute of a pin, and value change can be
- requested with the same attribute with ``DPLL_CMD_PIN_SET`` command.
- =============================== ======================================
- ``DPLL_A_PIN_ID`` configured pin id
- ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment
- ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment
- ``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
- adjustment on parent dpll device
- ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting
- configuration on given parent dpll
- device
- ``DPLL_A_PIN_PARENT_ID`` parent dpll device id
- ``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
- between a pin and parent dpll device
- =============================== ======================================
- All phase related values are provided in pico seconds, which represents
- time difference between signals phase. The negative value means that
- phase of signal on pin is earlier in time than dpll's signal. Positive
- value means that phase of signal on pin is later in time than signal of
- a dpll.
- Phase adjust (also min and max) values are integers, but measured phase
- offset values are fractional with 3-digit decimal places and shell be
- divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
- modulo divided to get fractional part.
- Embedded SYNC
- =============
- Device may provide ability to use Embedded SYNC feature. It allows
- to embed additional SYNC signal into the base frequency of a pin - a one
- special pulse of base frequency signal every time SYNC signal pulse
- happens. The user can configure the frequency of Embedded SYNC.
- The Embedded SYNC capability is always related to a given base frequency
- and HW capabilities. The user is provided a range of Embedded SYNC
- frequencies supported, depending on current base frequency configured for
- the pin.
- ========================================= =================================
- ``DPLL_A_PIN_ESYNC_FREQUENCY`` current Embedded SYNC frequency
- ``DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED`` nest available Embedded SYNC
- frequency ranges
- ``DPLL_A_PIN_FREQUENCY_MIN`` attr minimum value of frequency
- ``DPLL_A_PIN_FREQUENCY_MAX`` attr maximum value of frequency
- ``DPLL_A_PIN_ESYNC_PULSE`` pulse type of Embedded SYNC
- ========================================= =================================
- Configuration commands group
- ============================
- Configuration commands are used to get information about registered
- dpll devices (and pins), as well as set configuration of device or pins.
- As dpll devices must be abstracted and reflect real hardware,
- there is no way to add new dpll device via netlink from user space and
- each device should be registered by its driver.
- All netlink commands require ``GENL_ADMIN_PERM``. This is to prevent
- any spamming/DoS from unauthorized userspace applications.
- List of netlink commands with possible attributes
- =================================================
- Constants identifying command types for dpll device uses a
- ``DPLL_CMD_`` prefix and suffix according to command purpose.
- The dpll device related attributes use a ``DPLL_A_`` prefix and
- suffix according to attribute purpose.
- ==================================== =================================
- ``DPLL_CMD_DEVICE_ID_GET`` command to get device ID
- ``DPLL_A_MODULE_NAME`` attr module name of registerer
- ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier
- (EUI-64), as defined by the
- IEEE 1588 standard
- ``DPLL_A_TYPE`` attr type of dpll device
- ==================================== =================================
- ==================================== =================================
- ``DPLL_CMD_DEVICE_GET`` command to get device info or
- dump list of available devices
- ``DPLL_A_ID`` attr unique dpll device ID
- ``DPLL_A_MODULE_NAME`` attr module name of registerer
- ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier
- (EUI-64), as defined by the
- IEEE 1588 standard
- ``DPLL_A_MODE`` attr selection mode
- ``DPLL_A_MODE_SUPPORTED`` attr available selection modes
- ``DPLL_A_LOCK_STATUS`` attr dpll device lock status
- ``DPLL_A_TEMP`` attr device temperature info
- ``DPLL_A_TYPE`` attr type of dpll device
- ==================================== =================================
- ==================================== =================================
- ``DPLL_CMD_DEVICE_SET`` command to set dpll device config
- ``DPLL_A_ID`` attr internal dpll device index
- ``DPLL_A_MODE`` attr selection mode to configure
- ==================================== =================================
- Constants identifying command types for pins uses a
- ``DPLL_CMD_PIN_`` prefix and suffix according to command purpose.
- The pin related attributes use a ``DPLL_A_PIN_`` prefix and suffix
- according to attribute purpose.
- ==================================== =================================
- ``DPLL_CMD_PIN_ID_GET`` command to get pin ID
- ``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer
- ``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier
- (EUI-64), as defined by the
- IEEE 1588 standard
- ``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided
- by registerer
- ``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided
- by registerer
- ``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided
- by registerer
- ``DPLL_A_PIN_TYPE`` attr type of a pin
- ==================================== =================================
- ==================================== ==================================
- ``DPLL_CMD_PIN_GET`` command to get pin info or dump
- list of available pins
- ``DPLL_A_PIN_ID`` attr unique a pin ID
- ``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer
- ``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier
- (EUI-64), as defined by the
- IEEE 1588 standard
- ``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided
- by registerer
- ``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided
- by registerer
- ``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided
- by registerer
- ``DPLL_A_PIN_TYPE`` attr type of a pin
- ``DPLL_A_PIN_FREQUENCY`` attr current frequency of a pin
- ``DPLL_A_PIN_FREQUENCY_SUPPORTED`` nested attr provides supported
- frequencies
- ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency
- ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency
- ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase
- adjustment
- ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase
- adjustment
- ``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
- adjustment on parent device
- ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device
- the pin is connected with
- ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id
- ``DPLL_A_PIN_PRIO`` attr priority of pin on the
- dpll device
- ``DPLL_A_PIN_STATE`` attr state of pin on the parent
- dpll device
- ``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the
- parent dpll device
- ``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
- between a pin and parent dpll
- ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
- the pin is connected with
- ``DPLL_A_PIN_PARENT_ID`` attr parent pin id
- ``DPLL_A_PIN_STATE`` attr state of pin on the parent
- pin
- ``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities
- ==================================== ==================================
- ==================================== =================================
- ``DPLL_CMD_PIN_SET`` command to set pins configuration
- ``DPLL_A_PIN_ID`` attr unique a pin ID
- ``DPLL_A_PIN_FREQUENCY`` attr requested frequency of a pin
- ``DPLL_A_PIN_PHASE_ADJUST`` attr requested value of phase
- adjustment on parent device
- ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent dpll
- device configuration request
- ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id
- ``DPLL_A_PIN_DIRECTION`` attr requested direction of a pin
- ``DPLL_A_PIN_PRIO`` attr requested priority of pin on
- the dpll device
- ``DPLL_A_PIN_STATE`` attr requested state of pin on
- the dpll device
- ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
- configuration request
- ``DPLL_A_PIN_PARENT_ID`` attr parent pin id
- ``DPLL_A_PIN_STATE`` attr requested state of pin on
- parent pin
- ==================================== =================================
- Netlink dump requests
- =====================
- The ``DPLL_CMD_DEVICE_GET`` and ``DPLL_CMD_PIN_GET`` commands are
- capable of dump type netlink requests, in which case the response is in
- the same format as for their ``do`` request, but every device or pin
- registered in the system is returned.
- SET commands format
- ===================
- ``DPLL_CMD_DEVICE_SET`` - to target a dpll device, the user provides
- ``DPLL_A_ID``, which is unique identifier of dpll device in the system,
- as well as parameter being configured (``DPLL_A_MODE``).
- ``DPLL_CMD_PIN_SET`` - to target a pin user must provide a
- ``DPLL_A_PIN_ID``, which is unique identifier of a pin in the system.
- Also configured pin parameters must be added.
- If ``DPLL_A_PIN_FREQUENCY`` is configured, this affects all the dpll
- devices that are connected with the pin, that is why frequency attribute
- shall not be enclosed in ``DPLL_A_PIN_PARENT_DEVICE``.
- Other attributes: ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE`` or
- ``DPLL_A_PIN_DIRECTION`` must be enclosed in
- ``DPLL_A_PIN_PARENT_DEVICE`` as their configuration relates to only one
- of parent dplls, targeted by ``DPLL_A_PIN_PARENT_ID`` attribute which is
- also required inside that nest.
- For MUX-type pins the ``DPLL_A_PIN_STATE`` attribute is configured in
- similar way, by enclosing required state in ``DPLL_A_PIN_PARENT_PIN``
- nested attribute and targeted parent pin id in ``DPLL_A_PIN_PARENT_ID``.
- In general, it is possible to configure multiple parameters at once, but
- internally each parameter change will be invoked separately, where order
- of configuration is not guaranteed by any means.
- Configuration pre-defined enums
- ===============================
- .. kernel-doc:: include/uapi/linux/dpll.h
- Notifications
- =============
- dpll device can provide notifications regarding status changes of the
- device, i.e. lock status changes, input/output changes or other alarms.
- There is one multicast group that is used to notify user-space apps via
- netlink socket: ``DPLL_MCGRP_MONITOR``
- Notifications messages:
- ============================== =====================================
- ``DPLL_CMD_DEVICE_CREATE_NTF`` dpll device was created
- ``DPLL_CMD_DEVICE_DELETE_NTF`` dpll device was deleted
- ``DPLL_CMD_DEVICE_CHANGE_NTF`` dpll device has changed
- ``DPLL_CMD_PIN_CREATE_NTF`` dpll pin was created
- ``DPLL_CMD_PIN_DELETE_NTF`` dpll pin was deleted
- ``DPLL_CMD_PIN_CHANGE_NTF`` dpll pin has changed
- ============================== =====================================
- Events format is the same as for the corresponding get command.
- Format of ``DPLL_CMD_DEVICE_`` events is the same as response of
- ``DPLL_CMD_DEVICE_GET``.
- Format of ``DPLL_CMD_PIN_`` events is same as response of
- ``DPLL_CMD_PIN_GET``.
- Device driver implementation
- ============================
- Device is allocated by dpll_device_get() call. Second call with the
- same arguments will not create new object but provides pointer to
- previously created device for given arguments, it also increases
- refcount of that object.
- Device is deallocated by dpll_device_put() call, which first
- decreases the refcount, once refcount is cleared the object is
- destroyed.
- Device should implement set of operations and register device via
- dpll_device_register() at which point it becomes available to the
- users. Multiple driver instances can obtain reference to it with
- dpll_device_get(), as well as register dpll device with their own
- ops and priv.
- The pins are allocated separately with dpll_pin_get(), it works
- similarly to dpll_device_get(). Function first creates object and then
- for each call with the same arguments only the object refcount
- increases. Also dpll_pin_put() works similarly to dpll_device_put().
- A pin can be registered with parent dpll device or parent pin, depending
- on hardware needs. Each registration requires registerer to provide set
- of pin callbacks, and private data pointer for calling them:
- - dpll_pin_register() - register pin with a dpll device,
- - dpll_pin_on_pin_register() - register pin with another MUX type pin.
- Notifications of adding or removing dpll devices are created within
- subsystem itself.
- Notifications about registering/deregistering pins are also invoked by
- the subsystem.
- Notifications about status changes either of dpll device or a pin are
- invoked in two ways:
- - after successful change was requested on dpll subsystem, the subsystem
- calls corresponding notification,
- - requested by device driver with dpll_device_change_ntf() or
- dpll_pin_change_ntf() when driver informs about the status change.
- The device driver using dpll interface is not required to implement all
- the callback operation. Nevertheless, there are few required to be
- implemented.
- Required dpll device level callback operations:
- - ``.mode_get``,
- - ``.lock_status_get``.
- Required pin level callback operations:
- - ``.state_on_dpll_get`` (pins registered with dpll device),
- - ``.state_on_pin_get`` (pins registered with parent pin),
- - ``.direction_get``.
- Every other operation handler is checked for existence and
- ``-EOPNOTSUPP`` is returned in case of absence of specific handler.
- The simplest implementation is in the OCP TimeCard driver. The ops
- structures are defined like this:
- .. code-block:: c
- static const struct dpll_device_ops dpll_ops = {
- .lock_status_get = ptp_ocp_dpll_lock_status_get,
- .mode_get = ptp_ocp_dpll_mode_get,
- .mode_supported = ptp_ocp_dpll_mode_supported,
- };
- static const struct dpll_pin_ops dpll_pins_ops = {
- .frequency_get = ptp_ocp_dpll_frequency_get,
- .frequency_set = ptp_ocp_dpll_frequency_set,
- .direction_get = ptp_ocp_dpll_direction_get,
- .direction_set = ptp_ocp_dpll_direction_set,
- .state_on_dpll_get = ptp_ocp_dpll_state_get,
- };
- The registration part is then looks like this part:
- .. code-block:: c
- clkid = pci_get_dsn(pdev);
- bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE);
- if (IS_ERR(bp->dpll)) {
- err = PTR_ERR(bp->dpll);
- dev_err(&pdev->dev, "dpll_device_alloc failed\n");
- goto out;
- }
- err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp);
- if (err)
- goto out;
- for (i = 0; i < OCP_SMA_NUM; i++) {
- bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop);
- if (IS_ERR(bp->sma[i].dpll_pin)) {
- err = PTR_ERR(bp->dpll);
- goto out_dpll;
- }
- err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops,
- &bp->sma[i]);
- if (err) {
- dpll_pin_put(bp->sma[i].dpll_pin);
- goto out_dpll;
- }
- }
- In the error path we have to rewind every allocation in the reverse order:
- .. code-block:: c
- while (i) {
- --i;
- dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
- dpll_pin_put(bp->sma[i].dpll_pin);
- }
- dpll_device_put(bp->dpll);
- More complex example can be found in Intel's ICE driver or nVidia's mlx5 driver.
- SyncE enablement
- ================
- For SyncE enablement it is required to allow control over dpll device
- for a software application which monitors and configures the inputs of
- dpll device in response to current state of a dpll device and its
- inputs.
- In such scenario, dpll device input signal shall be also configurable
- to drive dpll with signal recovered from the PHY netdevice.
- This is done by exposing a pin to the netdevice - attaching pin to the
- netdevice itself with
- ``dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)``.
- Exposed pin id handle ``DPLL_A_PIN_ID`` is then identifiable by the user
- as it is attached to rtnetlink respond to get ``RTM_NEWLINK`` command in
- nested attribute ``IFLA_DPLL_PIN``.
|