rtc: isl1208: Add isl1208_set_xtoscb()
authorBiju Das <biju.das.jz@bp.renesas.com>
Fri, 23 Jun 2023 14:09:47 +0000 (15:09 +0100)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Sun, 25 Jun 2023 22:58:21 +0000 (00:58 +0200)
As per the HW manual, set the XTOSCB bit as follows:

If using an external clock signal, set the XTOSCB bit as 1 to
disable the crystal oscillator.

If using an external crystal, the XTOSCB bit needs to be set at 0
to enable the crystal oscillator.

Add isl1208_set_xtoscb() to set XTOSCB bit based on the clock-names
property. Fallback is enabling the internal crystal oscillator.

While at it, introduce a variable "sr" for reading the status register
in probe() as it is reused for writing and also remove the unnecessary
blank line.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://lore.kernel.org/r/20230623140948.384762-10-biju.das.jz@bp.renesas.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/rtc/rtc-isl1208.c

index 42d2116..e9ec567 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <linux/bcd.h>
+#include <linux/clk.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
@@ -175,6 +176,20 @@ isl1208_i2c_validate_client(struct i2c_client *client)
        return 0;
 }
 
+static int isl1208_set_xtoscb(struct i2c_client *client, int sr, int xtosb_val)
+{
+       /* Do nothing if bit is already set to desired value */
+       if ((sr & ISL1208_REG_SR_XTOSCB) == xtosb_val)
+               return 0;
+
+       if (xtosb_val)
+               sr |= ISL1208_REG_SR_XTOSCB;
+       else
+               sr &= ~ISL1208_REG_SR_XTOSCB;
+
+       return i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
+}
+
 static int
 isl1208_i2c_get_sr(struct i2c_client *client)
 {
@@ -511,7 +526,6 @@ isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
        return 0;
 }
 
-
 static int
 isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
@@ -806,11 +820,25 @@ static int isl1208_setup_irq(struct i2c_client *client, int irq)
 }
 
 static int
+isl1208_clk_present(struct i2c_client *client, const char *name)
+{
+       struct clk *clk;
+
+       clk = devm_clk_get_optional(&client->dev, name);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       return !!clk;
+}
+
+static int
 isl1208_probe(struct i2c_client *client)
 {
-       int rc = 0;
        struct isl1208_state *isl1208;
        int evdet_irq = -1;
+       int xtosb_val = 0;
+       int rc = 0;
+       int sr;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
@@ -837,6 +865,19 @@ isl1208_probe(struct i2c_client *client)
                isl1208->config = (struct isl1208_config *)id->driver_data;
        }
 
+       rc = isl1208_clk_present(client, "xin");
+       if (rc < 0)
+               return rc;
+
+       if (!rc) {
+               rc = isl1208_clk_present(client, "clkin");
+               if (rc < 0)
+                       return rc;
+
+               if (rc)
+                       xtosb_val = 1;
+       }
+
        isl1208->rtc = devm_rtc_allocate_device(&client->dev);
        if (IS_ERR(isl1208->rtc))
                return PTR_ERR(isl1208->rtc);
@@ -848,13 +889,17 @@ isl1208_probe(struct i2c_client *client)
        isl1208->nvmem_config.size = isl1208->config->nvmem_length;
        isl1208->nvmem_config.priv = isl1208;
 
-       rc = isl1208_i2c_get_sr(client);
-       if (rc < 0) {
+       sr = isl1208_i2c_get_sr(client);
+       if (sr < 0) {
                dev_err(&client->dev, "reading status failed\n");
-               return rc;
+               return sr;
        }
 
-       if (rc & ISL1208_REG_SR_RTCF)
+       rc = isl1208_set_xtoscb(client, sr, xtosb_val);
+       if (rc)
+               return rc;
+
+       if (sr & ISL1208_REG_SR_RTCF)
                dev_warn(&client->dev, "rtc power failure detected, "
                         "please set clock.\n");