From nobody Mon Feb 9 03:11:56 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 13968EB64D7 for ; Fri, 23 Jun 2023 12:45:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231732AbjFWMpb (ORCPT ); Fri, 23 Jun 2023 08:45:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231675AbjFWMpW (ORCPT ); Fri, 23 Jun 2023 08:45:22 -0400 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B98A8271F; Fri, 23 Jun 2023 05:44:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1687524288; x=1719060288; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MS8ia/YxJ1/98BjLyc2hMl6rgQuqLObEQYsxG8+HpnE=; b=A4vc6CFkieezDP+zykCLfejMhzXDKnIhzdetCYt1Cb3OMR0SMRA07xkf gvNR1FhpyYysgEsoEeC/i76JuUjagvB7LkhpU36XLpi1LuegPl9Utwr2t ARQOnRBTl6ewTTqpHNYZ1RVvWKJfmfyaAtxIKnzmtEzf61kIKOu2hDntL pGn6T6mEDGX2WIJoowUmgMcz6p5HNS01imHtySnQ+XE7BE44qK7rd+Jjf M4MAKyZHoZwWxklmlkU2Gj+75nQuKTnuQi+RVZY1dWqtdmxnlvjIDX2kL OWAeiyx5Itd+6CT0wc0b4r/TMwlmfSHpYDDxqocf35nFw5TzuPcZM7NVF A==; X-IronPort-AV: E=McAfee;i="6600,9927,10750"; a="341096893" X-IronPort-AV: E=Sophos;i="6.01,152,1684825200"; d="scan'208";a="341096893" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jun 2023 05:42:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10750"; a="785321263" X-IronPort-AV: E=Sophos;i="6.01,152,1684825200"; d="scan'208";a="785321263" Received: from amlin-018-114.igk.intel.com ([10.102.18.114]) by fmsmga004.fm.intel.com with ESMTP; 23 Jun 2023 05:41:51 -0700 From: Arkadiusz Kubalewski To: kuba@kernel.org, jiri@resnulli.us, arkadiusz.kubalewski@intel.com, vadfed@meta.com, jonathan.lemon@gmail.com, pabeni@redhat.com Cc: corbet@lwn.net, davem@davemloft.net, edumazet@google.com, vadfed@fb.com, jesse.brandeburg@intel.com, anthony.l.nguyen@intel.com, saeedm@nvidia.com, leon@kernel.org, richardcochran@gmail.com, sj@kernel.org, javierm@redhat.com, ricardo.canuelo@collabora.com, mst@redhat.com, tzimmermann@suse.de, michal.michalik@intel.com, gregkh@linuxfoundation.org, jacek.lawrynowicz@linux.intel.com, airlied@redhat.com, ogabbay@kernel.org, arnd@arndb.de, nipun.gupta@amd.com, axboe@kernel.dk, linux@zary.sk, masahiroy@kernel.org, benjamin.tissoires@redhat.com, geert+renesas@glider.be, milena.olech@intel.com, kuniyu@amazon.com, liuhangbin@gmail.com, hkallweit1@gmail.com, andy.ren@getcruise.com, razor@blackwall.org, idosch@nvidia.com, lucien.xin@gmail.com, nicolas.dichtel@6wind.com, phil@nwl.cc, claudiajkang@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org, linux-rdma@vger.kernel.org, linux-arm-kernel@lists.infradead.org, poros@redhat.com, mschmidt@redhat.com, linux-clk@vger.kernel.org, vadim.fedorenko@linux.dev Subject: [RFC PATCH v9 09/10] ptp_ocp: implement DPLL ops Date: Fri, 23 Jun 2023 14:38:19 +0200 Message-Id: <20230623123820.42850-10-arkadiusz.kubalewski@intel.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20230623123820.42850-1-arkadiusz.kubalewski@intel.com> References: <20230623123820.42850-1-arkadiusz.kubalewski@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Vadim Fedorenko Implement basic DPLL operations in ptp_ocp driver as the simplest example of using new subsystem. Signed-off-by: Vadim Fedorenko Signed-off-by: Arkadiusz Kubalewski --- drivers/ptp/Kconfig | 1 + drivers/ptp/ptp_ocp.c | 329 +++++++++++++++++++++++++++++++++++------- 2 files changed, 278 insertions(+), 52 deletions(-) diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 32dff1b4f891..e4da62ac9a9f 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -177,6 +177,7 @@ config PTP_1588_CLOCK_OCP depends on COMMON_CLK select NET_DEVLINK select CRC16 + select DPLL help This driver adds support for an OpenCompute time card. =20 diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index ab8cab4d1560..40a1ab7053d4 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -23,6 +23,7 @@ #include #include #include +#include =20 #define PCI_VENDOR_ID_FACEBOOK 0x1d9b #define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 @@ -260,12 +261,21 @@ enum ptp_ocp_sma_mode { SMA_MODE_OUT, }; =20 +static struct dpll_pin_frequency ptp_ocp_sma_freq[] =3D { + DPLL_PIN_FREQUENCY_1PPS, + DPLL_PIN_FREQUENCY_10MHZ, + DPLL_PIN_FREQUENCY_IRIG_B, + DPLL_PIN_FREQUENCY_DCF77, +}; + struct ptp_ocp_sma_connector { enum ptp_ocp_sma_mode mode; bool fixed_fcn; bool fixed_dir; bool disabled; u8 default_fcn; + struct dpll_pin *dpll_pin; + struct dpll_pin_properties dpll_prop; }; =20 struct ocp_attr_group { @@ -294,6 +304,7 @@ struct ptp_ocp_serial_port { =20 #define OCP_BOARD_ID_LEN 13 #define OCP_SERIAL_LEN 6 +#define OCP_SMA_NUM 4 =20 struct ptp_ocp { struct pci_dev *pdev; @@ -350,8 +361,9 @@ struct ptp_ocp { u32 ts_window_adjust; u64 fw_cap; struct ptp_ocp_signal signal[4]; - struct ptp_ocp_sma_connector sma[4]; + struct ptp_ocp_sma_connector sma[OCP_SMA_NUM]; const struct ocp_sma_op *sma_op; + struct dpll_device *dpll; }; =20 #define OCP_REQ_TIMESTAMP BIT(0) @@ -835,6 +847,7 @@ static DEFINE_IDR(ptp_ocp_idr); struct ocp_selector { const char *name; int value; + u64 frequency; }; =20 static const struct ocp_selector ptp_ocp_clock[] =3D { @@ -855,31 +868,31 @@ static const struct ocp_selector ptp_ocp_clock[] =3D { #define SMA_SELECT_MASK GENMASK(14, 0) =20 static const struct ocp_selector ptp_ocp_sma_in[] =3D { - { .name =3D "10Mhz", .value =3D 0x0000 }, - { .name =3D "PPS1", .value =3D 0x0001 }, - { .name =3D "PPS2", .value =3D 0x0002 }, - { .name =3D "TS1", .value =3D 0x0004 }, - { .name =3D "TS2", .value =3D 0x0008 }, - { .name =3D "IRIG", .value =3D 0x0010 }, - { .name =3D "DCF", .value =3D 0x0020 }, - { .name =3D "TS3", .value =3D 0x0040 }, - { .name =3D "TS4", .value =3D 0x0080 }, - { .name =3D "FREQ1", .value =3D 0x0100 }, - { .name =3D "FREQ2", .value =3D 0x0200 }, - { .name =3D "FREQ3", .value =3D 0x0400 }, - { .name =3D "FREQ4", .value =3D 0x0800 }, - { .name =3D "None", .value =3D SMA_DISABLE }, + { .name =3D "10Mhz", .value =3D 0x0000, .frequency =3D 10000000 }, + { .name =3D "PPS1", .value =3D 0x0001, .frequency =3D 1 }, + { .name =3D "PPS2", .value =3D 0x0002, .frequency =3D 1 }, + { .name =3D "TS1", .value =3D 0x0004, .frequency =3D 0 }, + { .name =3D "TS2", .value =3D 0x0008, .frequency =3D 0 }, + { .name =3D "IRIG", .value =3D 0x0010, .frequency =3D 10000 }, + { .name =3D "DCF", .value =3D 0x0020, .frequency =3D 77500 }, + { .name =3D "TS3", .value =3D 0x0040, .frequency =3D 0 }, + { .name =3D "TS4", .value =3D 0x0080, .frequency =3D 0 }, + { .name =3D "FREQ1", .value =3D 0x0100, .frequency =3D 0 }, + { .name =3D "FREQ2", .value =3D 0x0200, .frequency =3D 0 }, + { .name =3D "FREQ3", .value =3D 0x0400, .frequency =3D 0 }, + { .name =3D "FREQ4", .value =3D 0x0800, .frequency =3D 0 }, + { .name =3D "None", .value =3D SMA_DISABLE, .frequency =3D 0 }, { } }; =20 static const struct ocp_selector ptp_ocp_sma_out[] =3D { - { .name =3D "10Mhz", .value =3D 0x0000 }, - { .name =3D "PHC", .value =3D 0x0001 }, - { .name =3D "MAC", .value =3D 0x0002 }, - { .name =3D "GNSS1", .value =3D 0x0004 }, - { .name =3D "GNSS2", .value =3D 0x0008 }, - { .name =3D "IRIG", .value =3D 0x0010 }, - { .name =3D "DCF", .value =3D 0x0020 }, + { .name =3D "10Mhz", .value =3D 0x0000, .frequency =3D 10000000 }, + { .name =3D "PHC", .value =3D 0x0001, .frequency =3D 1 }, + { .name =3D "MAC", .value =3D 0x0002, .frequency =3D 1 }, + { .name =3D "GNSS1", .value =3D 0x0004, .frequency =3D 1 }, + { .name =3D "GNSS2", .value =3D 0x0008, .frequency =3D 1 }, + { .name =3D "IRIG", .value =3D 0x0010, .frequency =3D 10000 }, + { .name =3D "DCF", .value =3D 0x0020, .frequency =3D 77000 }, { .name =3D "GEN1", .value =3D 0x0040 }, { .name =3D "GEN2", .value =3D 0x0080 }, { .name =3D "GEN3", .value =3D 0x0100 }, @@ -890,15 +903,15 @@ static const struct ocp_selector ptp_ocp_sma_out[] = =3D { }; =20 static const struct ocp_selector ptp_ocp_art_sma_in[] =3D { - { .name =3D "PPS1", .value =3D 0x0001 }, - { .name =3D "10Mhz", .value =3D 0x0008 }, + { .name =3D "PPS1", .value =3D 0x0001, .frequency =3D 1 }, + { .name =3D "10Mhz", .value =3D 0x0008, .frequency =3D 1000000 }, { } }; =20 static const struct ocp_selector ptp_ocp_art_sma_out[] =3D { - { .name =3D "PHC", .value =3D 0x0002 }, - { .name =3D "GNSS", .value =3D 0x0004 }, - { .name =3D "10Mhz", .value =3D 0x0010 }, + { .name =3D "PHC", .value =3D 0x0002, .frequency =3D 1 }, + { .name =3D "GNSS", .value =3D 0x0004, .frequency =3D 1 }, + { .name =3D "10Mhz", .value =3D 0x0010, .frequency =3D 10000000 }, { } }; =20 @@ -2282,22 +2295,35 @@ ptp_ocp_sma_fb_set_inputs(struct ptp_ocp *bp, int s= ma_nr, u32 val) static void ptp_ocp_sma_fb_init(struct ptp_ocp *bp) { + struct dpll_pin_properties prop =3D { + .board_label =3D NULL, + .type =3D DPLL_PIN_TYPE_EXT, + .capabilities =3D DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE, + .freq_supported_num =3D ARRAY_SIZE(ptp_ocp_sma_freq), + .freq_supported =3D ptp_ocp_sma_freq, + + }; u32 reg; int i; =20 /* defaults */ + for (i =3D 0; i < OCP_SMA_NUM; i++) { + bp->sma[i].default_fcn =3D i & 1; + bp->sma[i].dpll_prop =3D prop; + bp->sma[i].dpll_prop.board_label =3D + bp->ptp_info.pin_config[i].name; + } bp->sma[0].mode =3D SMA_MODE_IN; bp->sma[1].mode =3D SMA_MODE_IN; bp->sma[2].mode =3D SMA_MODE_OUT; bp->sma[3].mode =3D SMA_MODE_OUT; - for (i =3D 0; i < 4; i++) - bp->sma[i].default_fcn =3D i & 1; - /* If no SMA1 map, the pin functions and directions are fixed. */ if (!bp->sma_map1) { - for (i =3D 0; i < 4; i++) { + for (i =3D 0; i < OCP_SMA_NUM; i++) { bp->sma[i].fixed_fcn =3D true; bp->sma[i].fixed_dir =3D true; + bp->sma[1].dpll_prop.capabilities &=3D + ~DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE; } return; } @@ -2307,7 +2333,7 @@ ptp_ocp_sma_fb_init(struct ptp_ocp *bp) */ reg =3D ioread32(&bp->sma_map2->gpio2); if (reg =3D=3D 0xffffffff) { - for (i =3D 0; i < 4; i++) + for (i =3D 0; i < OCP_SMA_NUM; i++) bp->sma[i].fixed_dir =3D true; } else { reg =3D ioread32(&bp->sma_map1->gpio1); @@ -2329,7 +2355,7 @@ static const struct ocp_sma_op ocp_fb_sma_op =3D { }; =20 static int -ptp_ocp_fb_set_pins(struct ptp_ocp *bp) +ptp_ocp_set_pins(struct ptp_ocp *bp) { struct ptp_pin_desc *config; int i; @@ -2396,16 +2422,16 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct oc= p_resource *r) =20 ptp_ocp_tod_init(bp); ptp_ocp_nmea_out_init(bp); - ptp_ocp_sma_init(bp); ptp_ocp_signal_init(bp); =20 err =3D ptp_ocp_attr_group_add(bp, fb_timecard_groups); if (err) return err; =20 - err =3D ptp_ocp_fb_set_pins(bp); + err =3D ptp_ocp_set_pins(bp); if (err) return err; + ptp_ocp_sma_init(bp); =20 return ptp_ocp_init_clock(bp); } @@ -2445,6 +2471,14 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kerne= l_ulong_t driver_data) static void ptp_ocp_art_sma_init(struct ptp_ocp *bp) { + struct dpll_pin_properties prop =3D { + .board_label =3D NULL, + .type =3D DPLL_PIN_TYPE_EXT, + .capabilities =3D 0, + .freq_supported_num =3D ARRAY_SIZE(ptp_ocp_sma_freq), + .freq_supported =3D ptp_ocp_sma_freq, + + }; u32 reg; int i; =20 @@ -2459,16 +2493,17 @@ ptp_ocp_art_sma_init(struct ptp_ocp *bp) bp->sma[2].default_fcn =3D 0x10; /* OUT: 10Mhz */ bp->sma[3].default_fcn =3D 0x02; /* OUT: PHC */ =20 - /* If no SMA map, the pin functions and directions are fixed. */ - if (!bp->art_sma) { - for (i =3D 0; i < 4; i++) { + + for (i =3D 0; i < OCP_SMA_NUM; i++) { + /* If no SMA map, the pin functions and directions are fixed. */ + bp->sma[i].dpll_prop =3D prop; + bp->sma[i].dpll_prop.board_label =3D + bp->ptp_info.pin_config[i].name; + if (!bp->art_sma) { bp->sma[i].fixed_fcn =3D true; bp->sma[i].fixed_dir =3D true; + continue; } - return; - } - - for (i =3D 0; i < 4; i++) { reg =3D ioread32(&bp->art_sma->map[i].gpio); =20 switch (reg & 0xff) { @@ -2479,9 +2514,13 @@ ptp_ocp_art_sma_init(struct ptp_ocp *bp) case 1: case 8: bp->sma[i].mode =3D SMA_MODE_IN; + bp->sma[i].dpll_prop.capabilities =3D + DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE; break; default: bp->sma[i].mode =3D SMA_MODE_OUT; + bp->sma[i].dpll_prop.capabilities =3D + DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE; break; } } @@ -2548,6 +2587,9 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp= _resource *r) /* Enable MAC serial port during initialisation */ iowrite32(1, &bp->board_config->mro50_serial_activate); =20 + err =3D ptp_ocp_set_pins(bp); + if (err) + return err; ptp_ocp_sma_init(bp); =20 err =3D ptp_ocp_attr_group_add(bp, art_timecard_groups); @@ -2689,16 +2731,9 @@ sma4_show(struct device *dev, struct device_attribut= e *attr, char *buf) } =20 static int -ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) +ptp_ocp_sma_store_val(struct ptp_ocp *bp, int val, enum ptp_ocp_sma_mode m= ode, int sma_nr) { struct ptp_ocp_sma_connector *sma =3D &bp->sma[sma_nr - 1]; - enum ptp_ocp_sma_mode mode; - int val; - - mode =3D sma->mode; - val =3D sma_parse_inputs(bp->sma_op->tbl, buf, &mode); - if (val < 0) - return val; =20 if (sma->fixed_dir && (mode !=3D sma->mode || val & SMA_DISABLE)) return -EOPNOTSUPP; @@ -2733,6 +2768,20 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *bu= f, int sma_nr) return val; } =20 +static int +ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) +{ + struct ptp_ocp_sma_connector *sma =3D &bp->sma[sma_nr - 1]; + enum ptp_ocp_sma_mode mode; + int val; + + mode =3D sma->mode; + val =3D sma_parse_inputs(bp->sma_op->tbl, buf, &mode); + if (val < 0) + return val; + return ptp_ocp_sma_store_val(bp, val, mode, sma_nr); +} + static ssize_t sma1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -4171,12 +4220,148 @@ ptp_ocp_detach(struct ptp_ocp *bp) device_unregister(&bp->dev); } =20 +static int ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, + void *priv, + enum dpll_lock_status *status, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp *bp =3D priv; + int sync; + + sync =3D ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; + *status =3D sync ? DPLL_LOCK_STATUS_LOCKED : DPLL_LOCK_STATUS_UNLOCKED; + + return 0; +} + +static int ptp_ocp_dpll_source_idx_get(const struct dpll_device *dpll, + void *priv, u32 *idx, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp *bp =3D priv; + + if (bp->pps_select) { + *idx =3D ioread32(&bp->pps_select->gpio1); + return 0; + } + return -EINVAL; +} + +static int ptp_ocp_dpll_mode_get(const struct dpll_device *dpll, void *pri= v, + u32 *mode, struct netlink_ext_ack *extack) +{ + *mode =3D DPLL_MODE_AUTOMATIC; + return 0; +} + +static bool ptp_ocp_dpll_mode_supported(const struct dpll_device *dpll, + void *priv, const enum dpll_mode mode, + struct netlink_ext_ack *extack) +{ + return mode =3D=3D DPLL_MODE_AUTOMATIC; +} + +static int ptp_ocp_dpll_direction_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma =3D pin_priv; + + *direction =3D sma->mode =3D=3D SMA_MODE_IN ? + DPLL_PIN_DIRECTION_INPUT : + DPLL_PIN_DIRECTION_OUTPUT; + return 0; +} + +static int ptp_ocp_dpll_direction_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_direction direction, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma =3D pin_priv; + struct ptp_ocp *bp =3D dpll_priv; + enum ptp_ocp_sma_mode mode; + int sma_nr =3D (sma - bp->sma); + + if (sma->fixed_dir) + return -EOPNOTSUPP; + mode =3D direction =3D=3D DPLL_PIN_DIRECTION_INPUT ? + SMA_MODE_IN : SMA_MODE_OUT; + return ptp_ocp_sma_store_val(bp, 0, mode, sma_nr); +} + +static int ptp_ocp_dpll_frequency_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 frequency, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma =3D pin_priv; + struct ptp_ocp *bp =3D dpll_priv; + const struct ocp_selector *tbl; + int sma_nr =3D (sma - bp->sma); + int val, i; + + if (sma->fixed_fcn) + return -EOPNOTSUPP; + + tbl =3D bp->sma_op->tbl[sma->mode]; + for (i =3D 0; tbl[i].name; i++) + if (tbl[i].frequency =3D=3D frequency) + return ptp_ocp_sma_store_val(bp, val, sma->mode, sma_nr); + return -EINVAL; +} + +static int ptp_ocp_dpll_frequency_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 *frequency, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma =3D pin_priv; + struct ptp_ocp *bp =3D dpll_priv; + const struct ocp_selector *tbl; + int sma_nr =3D (sma - bp->sma); + u32 val; + int i; + + val =3D bp->sma_op->get(bp, sma_nr); + tbl =3D bp->sma_op->tbl[sma->mode]; + for (i =3D 0; tbl[i].name; i++) + if (val =3D=3D tbl[i].value) { + *frequency =3D tbl[i].frequency; + return 0; + } + + return -EINVAL; +} + +static const struct dpll_device_ops dpll_ops =3D { + .lock_status_get =3D ptp_ocp_dpll_lock_status_get, + .source_pin_idx_get =3D ptp_ocp_dpll_source_idx_get, + .mode_get =3D ptp_ocp_dpll_mode_get, + .mode_supported =3D ptp_ocp_dpll_mode_supported, +}; + +static const struct dpll_pin_ops dpll_pins_ops =3D { + .frequency_get =3D ptp_ocp_dpll_frequency_get, + .frequency_set =3D ptp_ocp_dpll_frequency_set, + .direction_get =3D ptp_ocp_dpll_direction_get, + .direction_set =3D ptp_ocp_dpll_direction_set, +}; + static int ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct devlink *devlink; struct ptp_ocp *bp; - int err; + int err, i; + u64 clkid; =20 devlink =3D devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev); if (!devlink) { @@ -4226,8 +4411,39 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci= _device_id *id) =20 ptp_ocp_info(bp); devlink_register(devlink); - return 0; =20 + clkid =3D pci_get_dsn(pdev); + bp->dpll =3D dpll_device_get(clkid, 0, THIS_MODULE); + if (IS_ERR(bp->dpll)) { + dev_err(&pdev->dev, "dpll_device_alloc failed\n"); + goto out; + } + + err =3D dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp); + if (err) + goto out; + + for (i =3D 0; i < OCP_SMA_NUM; i++) { + bp->sma[i].dpll_pin =3D dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].= dpll_prop); + if (IS_ERR(bp->sma[i].dpll_pin)) + goto out_dpll; + + err =3D 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; + } + } + + return 0; +out_dpll: + 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); out: ptp_ocp_detach(bp); out_disable: @@ -4242,7 +4458,16 @@ ptp_ocp_remove(struct pci_dev *pdev) { struct ptp_ocp *bp =3D pci_get_drvdata(pdev); struct devlink *devlink =3D priv_to_devlink(bp); + int i; =20 + for (i =3D 0; i < OCP_SMA_NUM; i++) { + if (bp->sma[i].dpll_pin) { + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp); + dpll_pin_put(bp->sma[i].dpll_pin); + } + } + dpll_device_unregister(bp->dpll, &dpll_ops, bp); + dpll_device_put(bp->dpll); devlink_unregister(devlink); ptp_ocp_detach(bp); pci_disable_device(pdev); --=20 2.39.3