diff --git a/Documentation/driver-api/dpllsim.rst b/Documentation/driver-api/dpllsim.rst
index e7c5ee93392c21..5109d67325f140 100644
--- a/Documentation/driver-api/dpllsim.rst
+++ b/Documentation/driver-api/dpllsim.rst
@@ -36,6 +36,9 @@ Pin directory ``/sys/kernel/config/dpllsim/<dev>/pins/<pin>/``:
(default 0, which is rejected)
``direction`` ``input`` or ``output`` (default ``input``), a ``mux`` pin
must be an input
+``prio`` Priority 0-255 used for automatic reference selection,
+ input pins only, output pins must keep the default
+ (default 128)
============= ===============================================================
The pin directory name becomes the board label of the pin. Pins are@@ -53,8 +56,10 @@ output, then make it live::
mkdir pins/gnss0
echo gnss > pins/gnss0/type
echo 1 > pins/gnss0/frequency
+ echo 0 > pins/gnss0/prio
mkdir pins/ext0
echo 10000000 > pins/ext0/frequency
+ echo 1 > pins/ext0/prio
mkdir pins/out0
echo 10000000 > pins/out0/frequency
echo output > pins/out0/directiondiff --git a/drivers/dpll/dpllsim/core.c b/drivers/dpll/dpllsim/core.c
index 97b3cf48772e7f..ee728a7f0c21bc 100644
--- a/drivers/dpll/dpllsim/core.c
+++ b/drivers/dpll/dpllsim/core.c
@@ -132,10 +132,40 @@ static ssize_t dpllsim_pin_frequency_store(struct config_item *item,
}
CONFIGFS_ATTR(dpllsim_pin_, frequency);
+static ssize_t dpllsim_pin_prio_show(struct config_item *item, char *page)
+{
+ struct dpllsim_pin *pin = to_dpllsim_pin(item);
+
+ guard(mutex)(&pin->dev->lock);
+ return sysfs_emit(page, "%u\n", pin->prio);
+}
+
+static ssize_t dpllsim_pin_prio_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct dpllsim_pin *pin = to_dpllsim_pin(item);
+ u32 val;
+ int err;
+
+ err = kstrtou32(page, 10, &val);
+ if (err)
+ return err;
+ if (val > DPLLSIM_PIN_PRIO_MAX)
+ return -EINVAL;
+
+ guard(mutex)(&pin->dev->lock);
+ if (dpllsim_dev_frozen(pin->dev))
+ return -EBUSY;
+ pin->prio = val;
+ return count;
+}
+CONFIGFS_ATTR(dpllsim_pin_, prio);
+
static struct configfs_attribute *dpllsim_pin_attrs[] = {
&dpllsim_pin_attr_type,
&dpllsim_pin_attr_direction,
&dpllsim_pin_attr_frequency,
+ &dpllsim_pin_attr_prio,
NULL,
};
@@ -178,6 +208,7 @@ static struct config_item *dpllsim_pins_make_item(struct config_group *group,
pin->dev = sim;
pin->type = DPLL_PIN_TYPE_EXT;
pin->direction = DPLL_PIN_DIRECTION_INPUT;
+ pin->prio = DPLLSIM_DEFAULT_PIN_PRIO;
list_add_tail(&pin->list, &sim->pin_list);
return &pin->item;
diff --git a/drivers/dpll/dpllsim/dpll.c b/drivers/dpll/dpllsim/dpll.c
index 2b0c053a7b6087..8a302c2537c880 100644
--- a/drivers/dpll/dpllsim/dpll.c
+++ b/drivers/dpll/dpllsim/dpll.c
@@ -116,11 +116,43 @@ static int dpllsim_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
return 0;
}
+static int dpllsim_pin_prio_get(const struct dpll_pin *pin, void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv, u32 *prio,
+ struct netlink_ext_ack *extack)
+{
+ struct dpllsim_pin *sim_pin = pin_priv;
+
+ guard(mutex)(&sim_pin->dev->lock);
+ *prio = sim_pin->prio;
+ return 0;
+}
+
+static int dpllsim_pin_prio_set(const struct dpll_pin *pin, void *pin_priv,
+ const struct dpll_device *dpll,
+ void *dpll_priv, u32 prio,
+ struct netlink_ext_ack *extack)
+{
+ struct dpllsim_pin *sim_pin = pin_priv;
+
+ if (prio > DPLLSIM_PIN_PRIO_MAX) {
+ NL_SET_ERR_MSG_FMT(extack, "Pin priority must be in range 0-%u",
+ DPLLSIM_PIN_PRIO_MAX);
+ return -EINVAL;
+ }
+
+ guard(mutex)(&sim_pin->dev->lock);
+ sim_pin->prio = prio;
+ return 0;
+}
+
static const struct dpll_pin_ops dpllsim_input_pin_ops = {
.frequency_get = dpllsim_pin_frequency_get,
.direction_get = dpllsim_pin_direction_get,
.state_on_dpll_get = dpllsim_pin_state_get,
.state_on_dpll_set = dpllsim_pin_state_set,
+ .prio_get = dpllsim_pin_prio_get,
+ .prio_set = dpllsim_pin_prio_set,
};
static const struct dpll_pin_ops dpllsim_output_pin_ops = {@@ -165,7 +197,8 @@ static void dpllsim_pin_props(struct dpllsim_pin *pin,
/* Capabilities follow the ops the pin is served by */
if (dpllsim_pin_select_ops(pin) == &dpllsim_input_pin_ops)
- prop->capabilities = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+ prop->capabilities = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE |
+ DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE;
else
prop->capabilities = 0;
}
@@ -191,6 +224,13 @@ static bool dpllsim_pin_direction_valid(const struct dpllsim_pin *pin)
pin->direction == DPLL_PIN_DIRECTION_INPUT;
}
+/* Priority is meaningful for input pins only */
+static bool dpllsim_pin_prio_valid(const struct dpllsim_pin *pin)
+{
+ return pin->direction == DPLL_PIN_DIRECTION_INPUT ||
+ pin->prio == DPLLSIM_DEFAULT_PIN_PRIO;
+}
+
static void dpllsim_pin_reset(struct dpllsim_pin *pin)
{
pin->ops = dpllsim_pin_select_ops(pin);@@ -205,7 +245,8 @@ static int dpllsim_order_pins(struct dpllsim_dev *sim)
list_for_each_entry(pin, &sim->pin_list, list) {
if (!dpllsim_pin_frequency_valid(pin) ||
- !dpllsim_pin_direction_valid(pin))
+ !dpllsim_pin_direction_valid(pin) ||
+ !dpllsim_pin_prio_valid(pin))
return -EINVAL;
count++;
}diff --git a/drivers/dpll/dpllsim/dpllsim.h b/drivers/dpll/dpllsim/dpllsim.h
index 73b846b66f79c7..f9fced337dc881 100644
--- a/drivers/dpll/dpllsim/dpllsim.h
+++ b/drivers/dpll/dpllsim/dpllsim.h
@@ -12,6 +12,9 @@
#include <linux/list.h>
#include <linux/mutex.h>
+#define DPLLSIM_DEFAULT_PIN_PRIO 128
+#define DPLLSIM_PIN_PRIO_MAX 255
+
#define DPLLSIM_MAX_PINS 128
struct dpllsim_dev;
@@ -21,10 +24,15 @@ struct dpllsim_pin {
struct list_head list;
struct dpllsim_dev *dev;
- /* Configuration, writable only until dpllsim_dev_frozen() */
+ /*
+ * Configuration, set through configfs only until
+ * dpllsim_dev_frozen(). The netlink prio setter changes prio at
+ * runtime under dev->lock.
+ */
enum dpll_pin_type type;
enum dpll_pin_direction direction;
u64 frequency;
+ u32 prio;
/* Resolved at live=1 */
int idx;--
2.56.0