Received: by 2002:a25:d7c1:0:0:0:0:0 with SMTP id o184csp1727707ybg; Sat, 19 Oct 2019 01:12:03 -0700 (PDT) X-Google-Smtp-Source: APXvYqzQ101BASJvGFqTU4kEGtYk/o0Fy3DX6vdsPUfNAGEWsYQpBnmFakq7hhHtq+Ohs1OR77Vq X-Received: by 2002:a05:6402:64f:: with SMTP id u15mr13886773edx.231.1571472722838; Sat, 19 Oct 2019 01:12:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571472722; cv=none; d=google.com; s=arc-20160816; b=Kuo5DxEBjv5ggjehZdeyom2jN58A7WgZrnR+7wek6GSCNPmoSMIYZjX7mpkL2XrAW6 phNBL4j6XSIrVjKmikbJBnX2/lN8EXG/8NElqMci5ksfbxju/Q6j8yjCHQ1xK4jgrZJa kcPYla4v3zC/tvsLH8BCEu300qIDJvpGSHUOXg8rMFYqurmvv6QpACoT/rgB7Io+vot3 VOpkwsOhd9CEs95N87fT4eEFk9MCWYJb76wEtyE3KR30sOzKlQMpoLRKDdEDJm/zeMnc f7Qay7a4647FcbFPPtlyKq4nyQh8BdwaTUJVblKseIOhjaSzVqV8elC+2oETv/QsCGGF gnaw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=vY5Yz1lUQlHtNuwNiImVoS2UWSm+Nvo/KthehoBX/Oc=; b=hmCKhkAHLptK2MCt4c4Jvk79Y3xv1QJ1kM1WaCfN1j2A4Aa3qkn7Wuzkb1PvoCku52 lstxx2timR1vXqV4xZXuj8PDf9/0m8IEjbxxMnY+bhsqMsVM4ZNgl9P8uv8vjQKTvAaX QAZT9+K3GHgc4wFhtl9giNH8+xGR5L5bmg0E+PI6GrnD8zYjP67mdblGjD5Uze38+hZT z5pNwki/YvXXIfJCaxBAyXeZxHekNi8kWBQCPqrEH1aZm4CKxw/oknGzHmPvXh1ZPbZf X3rkTboi8nJeVscOe/sK44IXgv+f6+LKkuF/VpoYh/7Kg+FTVlhvmTrFaOUODg9/Q6Fe Lpzw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n19si5022685edo.172.2019.10.19.01.11.39; Sat, 19 Oct 2019 01:12:02 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2633203AbfJRKEm (ORCPT + 99 others); Fri, 18 Oct 2019 06:04:42 -0400 Received: from mail-out.m-online.net ([212.18.0.10]:56676 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389081AbfJRKEm (ORCPT ); Fri, 18 Oct 2019 06:04:42 -0400 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 46vhTg0Lh4z1rVvB; Fri, 18 Oct 2019 12:04:39 +0200 (CEST) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 46vhTf6sWRz1qqkL; Fri, 18 Oct 2019 12:04:38 +0200 (CEST) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id ED96pv6iFS6i; Fri, 18 Oct 2019 12:04:37 +0200 (CEST) X-Auth-Info: fEgBRx0OFy/2mFPZeh5pUUG3V60yj6jheJeiqsA7SjI= Received: from xpert.denx.de (unknown [62.91.23.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Fri, 18 Oct 2019 12:04:37 +0200 (CEST) From: Parthiban Nallathambi To: a.zummo@towertech.it, alexandre.belloni@bootlin.com Cc: linux-rtc@vger.kernel.org, linux-kernel@vger.kernel.org, parthitce@gmail.com, Parthiban Nallathambi Subject: [PATCH v2] rtc: rv3028: add clkout support Date: Fri, 18 Oct 2019 12:04:25 +0200 Message-Id: <20191018100425.1687979-1-pn@denx.de> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org rv3028 provides clkout (enabled by default). Add clkout to clock framework source and control from device tree for variable frequency with enable and disable functionality. Signed-off-by: Parthiban Nallathambi --- Notes: Notes: Changlog in v2: - Removed disabling the clock. clk core will disable it when no consumer is detected - Remove multiple write to CLKF drivers/rtc/rtc-rv3028.c | 146 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 2b316661a578..6b7b3a69601a 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -52,6 +53,11 @@ #define RV3028_STATUS_CLKF BIT(6) #define RV3028_STATUS_EEBUSY BIT(7) +#define RV3028_CLKOUT_FD_MASK GENMASK(2, 0) +#define RV3028_CLKOUT_PORIE BIT(3) +#define RV3028_CLKOUT_CLKSY BIT(6) +#define RV3028_CLKOUT_CLKOE BIT(7) + #define RV3028_CTRL1_EERD BIT(3) #define RV3028_CTRL1_WADA BIT(5) @@ -84,6 +90,9 @@ struct rv3028_data { struct regmap *regmap; struct rtc_device *rtc; enum rv3028_type type; +#ifdef CONFIG_COMMON_CLK + struct clk_hw clkout_hw; +#endif }; static u16 rv3028_trickle_resistors[] = {1000, 3000, 6000, 11000}; @@ -581,6 +590,140 @@ static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val, return ret; } +#ifdef CONFIG_COMMON_CLK +#define clkout_hw_to_rv3028(hw) container_of(hw, struct rv3028_data, clkout_hw) + +static int clkout_rates[] = { + 32768, + 8192, + 1024, + 64, + 32, + 1, +}; + +static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int clkout, ret; + struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); + + ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout); + if (ret < 0) + return 0; + + clkout &= RV3028_CLKOUT_FD_MASK; + return clkout_rates[clkout]; +} + +static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] <= rate) + return clkout_rates[i]; + + return 0; +} + +static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i, ret; + struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); + + ret = regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) { + if (clkout_rates[i] == rate) { + ret = regmap_update_bits(rv3028->regmap, + RV3028_CLKOUT, + RV3028_CLKOUT_FD_MASK, i); + if (ret < 0) + return ret; + + return regmap_write(rv3028->regmap, RV3028_CLKOUT, + RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE); + } + } + + return -EINVAL; +} + +static int rv3028_clkout_prepare(struct clk_hw *hw) +{ + struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); + + return regmap_write(rv3028->regmap, RV3028_CLKOUT, + RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE); +} + +static void rv3028_clkout_unprepare(struct clk_hw *hw) +{ + struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); + + regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0); + regmap_update_bits(rv3028->regmap, RV3028_STATUS, + RV3028_STATUS_CLKF, 0); +} + +static int rv3028_clkout_is_prepared(struct clk_hw *hw) +{ + int clkout, ret; + struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); + + ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout); + if (ret < 0) + return ret; + + return !!(clkout & RV3028_CLKOUT_CLKOE); +} + +static const struct clk_ops rv3028_clkout_ops = { + .prepare = rv3028_clkout_prepare, + .unprepare = rv3028_clkout_unprepare, + .is_prepared = rv3028_clkout_is_prepared, + .recalc_rate = rv3028_clkout_recalc_rate, + .round_rate = rv3028_clkout_round_rate, + .set_rate = rv3028_clkout_set_rate, +}; + +static int rv3028_clkout_register_clk(struct rv3028_data *rv3028, + struct i2c_client *client) +{ + int ret; + struct clk *clk; + struct clk_init_data init; + struct device_node *node = client->dev.of_node; + + ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS, + RV3028_STATUS_CLKF, 0); + if (ret < 0) + return ret; + + init.name = "rv3028-clkout"; + init.ops = &rv3028_clkout_ops; + init.flags = 0; + init.parent_names = NULL; + init.num_parents = 0; + rv3028->clkout_hw.init = &init; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + /* register the clock */ + clk = devm_clk_register(&client->dev, &rv3028->clkout_hw); + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return 0; +} +#endif + static struct rtc_class_ops rv3028_rtc_ops = { .read_time = rv3028_get_time, .set_time = rv3028_set_time, @@ -708,6 +851,9 @@ static int rv3028_probe(struct i2c_client *client) rv3028->rtc->max_user_freq = 1; +#ifdef CONFIG_COMMON_CLK + rv3028_clkout_register_clk(rv3028, client); +#endif return 0; } -- 2.21.0