aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>2013-05-03 01:33:27 -0400
committerMike Turquette <mturquette@linaro.org>2013-05-29 01:50:31 -0400
commit1a0483d2a4c2c5e218d415c90d1a62b3b917d34e (patch)
tree14f9c34645c52c16e1a0d32986629b0fdeb0f153
parent555eae97358082be3a46572464829c27b96ed8f1 (diff)
clk: si5351: Allow user to define disabled state for every clock output
This patch adds platform data and DT bindings to allow to overwrite the stored disabled state for each clock output. Signed-off-by: Marek Belisko <marek.belisko@streamunlimited.com> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/clock/silabs,si5351.txt5
-rw-r--r--drivers/clk/clk-si5351.c74
-rw-r--r--drivers/clk/clk-si5351.h1
-rw-r--r--include/linux/platform_data/si5351.h18
4 files changed, 95 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.txt b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
index cc374651662c..66c75b2d6158 100644
--- a/Documentation/devicetree/bindings/clock/silabs,si5351.txt
+++ b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
@@ -44,6 +44,11 @@ Optional child node properties:
44- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth 44- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
45 divider. 45 divider.
46- silabs,pll-master: boolean, multisynth can change pll frequency. 46- silabs,pll-master: boolean, multisynth can change pll frequency.
47- silabs,disable-state : clock output disable state, shall be
48 0 = clock output is driven LOW when disabled
49 1 = clock output is driven HIGH when disabled
50 2 = clock output is FLOATING (HIGH-Z) when disabled
51 3 = clock output is NEVER disabled
47 52
48==Example== 53==Example==
49 54
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index 892728412e9d..efc6d5e9268b 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -851,6 +851,41 @@ static int _si5351_clkout_set_drive_strength(
851 return 0; 851 return 0;
852} 852}
853 853
854static int _si5351_clkout_set_disable_state(
855 struct si5351_driver_data *drvdata, int num,
856 enum si5351_disable_state state)
857{
858 u8 reg = (num < 4) ? SI5351_CLK3_0_DISABLE_STATE :
859 SI5351_CLK7_4_DISABLE_STATE;
860 u8 shift = (num < 4) ? (2 * num) : (2 * (num-4));
861 u8 mask = SI5351_CLK_DISABLE_STATE_MASK << shift;
862 u8 val;
863
864 if (num > 8)
865 return -EINVAL;
866
867 switch (state) {
868 case SI5351_DISABLE_LOW:
869 val = SI5351_CLK_DISABLE_STATE_LOW;
870 break;
871 case SI5351_DISABLE_HIGH:
872 val = SI5351_CLK_DISABLE_STATE_HIGH;
873 break;
874 case SI5351_DISABLE_FLOATING:
875 val = SI5351_CLK_DISABLE_STATE_FLOAT;
876 break;
877 case SI5351_DISABLE_NEVER:
878 val = SI5351_CLK_DISABLE_STATE_NEVER;
879 break;
880 default:
881 return 0;
882 }
883
884 si5351_set_bits(drvdata, reg, mask, val << shift);
885
886 return 0;
887}
888
854static int si5351_clkout_prepare(struct clk_hw *hw) 889static int si5351_clkout_prepare(struct clk_hw *hw)
855{ 890{
856 struct si5351_hw_data *hwdata = 891 struct si5351_hw_data *hwdata =
@@ -1225,6 +1260,33 @@ static int si5351_dt_parse(struct i2c_client *client)
1225 } 1260 }
1226 } 1261 }
1227 1262
1263 if (!of_property_read_u32(child, "silabs,disable-state",
1264 &val)) {
1265 switch (val) {
1266 case 0:
1267 pdata->clkout[num].disable_state =
1268 SI5351_DISABLE_LOW;
1269 break;
1270 case 1:
1271 pdata->clkout[num].disable_state =
1272 SI5351_DISABLE_HIGH;
1273 break;
1274 case 2:
1275 pdata->clkout[num].disable_state =
1276 SI5351_DISABLE_FLOATING;
1277 break;
1278 case 3:
1279 pdata->clkout[num].disable_state =
1280 SI5351_DISABLE_NEVER;
1281 break;
1282 default:
1283 dev_err(&client->dev,
1284 "invalid disable state %d for clkout %d\n",
1285 val, num);
1286 return -EINVAL;
1287 }
1288 }
1289
1228 if (!of_property_read_u32(child, "clock-frequency", &val)) 1290 if (!of_property_read_u32(child, "clock-frequency", &val))
1229 pdata->clkout[num].rate = val; 1291 pdata->clkout[num].rate = val;
1230 1292
@@ -1281,9 +1343,6 @@ static int si5351_i2c_probe(struct i2c_client *client,
1281 1343
1282 /* Disable interrupts */ 1344 /* Disable interrupts */
1283 si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0); 1345 si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0);
1284 /* Set disabled output drivers to drive low */
1285 si5351_reg_write(drvdata, SI5351_CLK3_0_DISABLE_STATE, 0x00);
1286 si5351_reg_write(drvdata, SI5351_CLK7_4_DISABLE_STATE, 0x00);
1287 /* Ensure pll select is on XTAL for Si5351A/B */ 1346 /* Ensure pll select is on XTAL for Si5351A/B */
1288 if (drvdata->variant != SI5351_VARIANT_C) 1347 if (drvdata->variant != SI5351_VARIANT_C)
1289 si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE, 1348 si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
@@ -1327,6 +1386,15 @@ static int si5351_i2c_probe(struct i2c_client *client,
1327 n, pdata->clkout[n].drive); 1386 n, pdata->clkout[n].drive);
1328 return ret; 1387 return ret;
1329 } 1388 }
1389
1390 ret = _si5351_clkout_set_disable_state(drvdata, n,
1391 pdata->clkout[n].disable_state);
1392 if (ret) {
1393 dev_err(&client->dev,
1394 "failed set disable state of clkout%d to %d\n",
1395 n, pdata->clkout[n].disable_state);
1396 return ret;
1397 }
1330 } 1398 }
1331 1399
1332 /* register xtal input clock gate */ 1400 /* register xtal input clock gate */
diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h
index af41b5080f43..c0dbf2676872 100644
--- a/drivers/clk/clk-si5351.h
+++ b/drivers/clk/clk-si5351.h
@@ -81,6 +81,7 @@
81 81
82#define SI5351_CLK3_0_DISABLE_STATE 24 82#define SI5351_CLK3_0_DISABLE_STATE 24
83#define SI5351_CLK7_4_DISABLE_STATE 25 83#define SI5351_CLK7_4_DISABLE_STATE 25
84#define SI5351_CLK_DISABLE_STATE_MASK 3
84#define SI5351_CLK_DISABLE_STATE_LOW 0 85#define SI5351_CLK_DISABLE_STATE_LOW 0
85#define SI5351_CLK_DISABLE_STATE_HIGH 1 86#define SI5351_CLK_DISABLE_STATE_HIGH 1
86#define SI5351_CLK_DISABLE_STATE_FLOAT 2 87#define SI5351_CLK_DISABLE_STATE_FLOAT 2
diff --git a/include/linux/platform_data/si5351.h b/include/linux/platform_data/si5351.h
index 92dabcaf6499..54334393ab92 100644
--- a/include/linux/platform_data/si5351.h
+++ b/include/linux/platform_data/si5351.h
@@ -79,6 +79,23 @@ enum si5351_drive_strength {
79}; 79};
80 80
81/** 81/**
82 * enum si5351_disable_state - Si5351 clock output disable state
83 * @SI5351_DISABLE_DEFAULT: default, do not change eeprom config
84 * @SI5351_DISABLE_LOW: CLKx is set to a LOW state when disabled
85 * @SI5351_DISABLE_HIGH: CLKx is set to a HIGH state when disabled
86 * @SI5351_DISABLE_FLOATING: CLKx is set to a FLOATING state when
87 * disabled
88 * @SI5351_DISABLE_NEVER: CLKx is NEVER disabled
89 */
90enum si5351_disable_state {
91 SI5351_DISABLE_DEFAULT = 0,
92 SI5351_DISABLE_LOW,
93 SI5351_DISABLE_HIGH,
94 SI5351_DISABLE_FLOATING,
95 SI5351_DISABLE_NEVER,
96};
97
98/**
82 * struct si5351_clkout_config - Si5351 clock output configuration 99 * struct si5351_clkout_config - Si5351 clock output configuration
83 * @clkout: clkout number 100 * @clkout: clkout number
84 * @multisynth_src: multisynth source clock 101 * @multisynth_src: multisynth source clock
@@ -91,6 +108,7 @@ struct si5351_clkout_config {
91 enum si5351_multisynth_src multisynth_src; 108 enum si5351_multisynth_src multisynth_src;
92 enum si5351_clkout_src clkout_src; 109 enum si5351_clkout_src clkout_src;
93 enum si5351_drive_strength drive; 110 enum si5351_drive_strength drive;
111 enum si5351_disable_state disable_state;
94 bool pll_master; 112 bool pll_master;
95 unsigned long rate; 113 unsigned long rate;
96}; 114};