From: Kuninori Morimoto <[email protected]>

Signed-off-by: Kuninori Morimoto <[email protected]>
Tested-by: Hiroyuki Yokoyama <[email protected]>
---
 .../devicetree/bindings/clock/cs2000-cp.txt        |  9 +++
 drivers/clk/clk-cs2000-cp.c                        | 73 +++++++++++++++++++++-
 2 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/cs2000-cp.txt 
b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
index 54e6df0..4c2f9cb 100644
--- a/Documentation/devicetree/bindings/clock/cs2000-cp.txt
+++ b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
@@ -8,6 +8,15 @@ Required properties:
 - clock-names:         CLK_IN : clk_in, XTI/REF_CLK : ref_clk
 - #clock-cells:                must be <0>
 
+Option properties:
+
+- auxoutsrc:           select AUX_OUT source from these.
+                               refclk:         Timing Reference Clock
+                               clk_in:         Frequency Reference Clock
+                               pllclkout:      PLL Clock Output
+                               push-pull:      PLL Lock/Unlock Indication
+                               open-drain:     PLL Lock/Unlock Indication
+
 Example:
 
 &i2c2 {
diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c
index 4df38c5..234e3b4 100644
--- a/drivers/clk/clk-cs2000-cp.c
+++ b/drivers/clk/clk-cs2000-cp.c
@@ -42,6 +42,8 @@
 /* DEVICE_CFG1 */
 #define RSEL(x)                (((x) & 0x3) << 3)
 #define RSEL_MASK      RSEL(0x3)
+#define AUXOUTSRC(x)   (((x) & 0x3) << 1)
+#define AUXOUTSRC_MASK AUXOUTSRC(0x3)
 #define ENDEV1         (0x1)
 
 /* DEVICE_CFG2 */
@@ -54,6 +56,8 @@
 #define ENDEV2         (0x1)
 
 /* FUNC_CFG1 */
+#define AUXLOCKCFG(x)  (((x) & 0x1) << 6)
+#define AUXLOCKCFG_MASK        AUXLOCKCFG(1)
 #define REFCLKDIV(x)   (((x) & 0x3) << 3)
 #define REFCLKDIV_MASK REFCLKDIV(0x3)
 
@@ -66,11 +70,20 @@
 #define REF_CLK        1
 #define CLK_MAX 2
 
+enum auxoutsrc {
+       AUXSRC_REFCLK = 0,
+       AUXSRC_CLKIN,
+       AUXSRC_PLLCLKOUT,
+       AUXSRC_PUSHPULL,
+       AUXSRC_OPENDRAIN,
+};
+
 struct cs2000_priv {
        struct clk_hw hw;
        struct i2c_client *client;
        struct clk *clk_in;
        struct clk *ref_clk;
+       enum auxoutsrc auxoutsrc;
 
        /* suspend/resume */
        unsigned long saved_rate;
@@ -111,9 +124,27 @@ static int cs2000_bset(struct cs2000_priv *priv, u8 addr, 
u8 mask, u8 val)
 static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
 {
        int ret;
+       u8 dcfg1, fcfg1;
+
+       dcfg1 = 0;
+       fcfg1 = 0;
+       if (enable)
+               dcfg1 |= ENDEV1;
+       switch (priv->auxoutsrc) {
+       case AUXSRC_REFCLK:
+       case AUXSRC_CLKIN:
+       case AUXSRC_PLLCLKOUT:
+               dcfg1 |= AUXOUTSRC(priv->auxoutsrc);
+               break;
+       case AUXSRC_OPENDRAIN:
+               fcfg1 |= AUXLOCKCFG(1);
+               /* fall though */
+       case AUXSRC_PUSHPULL:
+               dcfg1 |= AUXOUTSRC(3);
+               break;
+       }
 
-       ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
-                         enable ? ENDEV1 : 0);
+       ret = cs2000_bset(priv, DEVICE_CFG1, (AUXOUTSRC_MASK | ENDEV1), dcfg1);
        if (ret < 0)
                return ret;
 
@@ -122,6 +153,10 @@ static int cs2000_enable_dev_config(struct cs2000_priv 
*priv, bool enable)
        if (ret < 0)
                return ret;
 
+       ret = cs2000_bset(priv, FUNC_CFG1, AUXLOCKCFG_MASK, fcfg1);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
@@ -479,6 +514,38 @@ static int cs2000_remove(struct i2c_client *client)
        return 0;
 }
 
+static void cs2000_of_parse(struct cs2000_priv *priv)
+{
+       struct device *dev = priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
+       const char *auxoutsrc;
+
+       auxoutsrc = of_get_property(np, "auxoutsrc", NULL);
+
+       if (auxoutsrc) {
+               int i;
+               struct {
+                       char *name;
+                       enum auxoutsrc val;
+               } of_table[] = {
+                       {"refclk",      AUXSRC_REFCLK},
+                       {"clk_in",      AUXSRC_CLKIN},
+                       {"pllclkout",   AUXSRC_PLLCLKOUT},
+                       {"push-pull",   AUXSRC_PUSHPULL},
+                       {"open-drain",  AUXSRC_OPENDRAIN},
+               };
+
+               for (i = 0; i < ARRAY_SIZE(of_table); i++) {
+                       if (strcmp(of_table[i].name, auxoutsrc) == 0) {
+                               priv->auxoutsrc = of_table[i].val;
+                               dev_dbg(dev, "%s was selected\n",
+                                       of_table[i].name);
+                               break;
+                       }
+               }
+       }
+}
+
 static int cs2000_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -493,6 +560,8 @@ static int cs2000_probe(struct i2c_client *client,
        priv->client = client;
        i2c_set_clientdata(client, priv);
 
+       cs2000_of_parse(priv);
+
        ret = cs2000_clk_get(priv);
        if (ret < 0)
                return ret;
-- 
1.9.1

Reply via email to