Skip to content

Commit 17231e4

Browse files
committed
drivers: iio: hmc7044.c Add OSCOUT as channel
Add OSCOUT as an output channel to the driver. Signed-off-by: George Mois <[email protected]>
1 parent e958f8a commit 17231e4

File tree

1 file changed

+155
-104
lines changed

1 file changed

+155
-104
lines changed

drivers/iio/frequency/hmc7044.c

Lines changed: 155 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
#define HMC7044_DYN_DRIVER_EN BIT(5)
215215
#define HMC7044_FORCE_MUTE_EN BIT(7)
216216

217-
#define HMC7044_NUM_CHAN 14
217+
#define HMC7044_NUM_CHAN 15
218218

219219
#define HMC7044_LOW_VCO_MIN 2150000
220220
#define HMC7044_LOW_VCO_MAX 2880000
@@ -309,11 +309,6 @@ struct hmc7044 {
309309
bool oscout_path_en;
310310
bool oscout0_driver_en;
311311
bool oscout1_driver_en;
312-
u32 oscout_divider_ratio;
313-
u32 oscout0_driver_mode;
314-
u32 oscout1_driver_mode;
315-
u32 oscout0_driver_impedance;
316-
u32 oscout1_driver_impedance;
317312
unsigned int sync_pin_mode;
318313
unsigned int pulse_gen_mode;
319314
unsigned int in_buf_mode[5];
@@ -449,6 +444,23 @@ static unsigned int hmc7044_calc_out_div(unsigned long parent_rate,
449444
return div;
450445
}
451446

447+
static unsigned int hmc7044_calc_oscout_div(unsigned long parent_rate,
448+
unsigned long rate)
449+
{
450+
unsigned int div;
451+
452+
div = DIV_ROUND_CLOSEST(parent_rate, rate);
453+
454+
/* Supported divide ratios are 1, 2, 4, and 8 */
455+
if (div == 1 || div == 2 || div == 4 || div == 8)
456+
return div;
457+
458+
if (div % 2)
459+
div--;
460+
461+
return (div == 6 || div > 8) ? 8 : div;
462+
}
463+
452464
static int hmc7044_read_raw(struct iio_dev *indio_dev,
453465
struct iio_chan_spec const *chan,
454466
int *val,
@@ -801,7 +813,17 @@ static long hmc7044_set_clk_attr(struct clk_hw *hw,
801813
static unsigned long hmc7044_clk_recalc_rate(struct clk_hw *hw,
802814
unsigned long parent_rate)
803815
{
804-
return hmc7044_get_clk_attr(hw, IIO_CHAN_INFO_FREQUENCY);
816+
struct hmc7044_output *out = to_output(hw);
817+
struct iio_dev *indio_dev = out->indio_dev;
818+
struct hmc7044 *hmc = iio_priv(indio_dev);
819+
struct hmc7044_chan_spec *ch;
820+
821+
ch = &hmc->channels[out->address];
822+
823+
if (ch->num == 14)
824+
return (hmc->vcxo_freq / ch->divider);
825+
else
826+
return hmc7044_get_clk_attr(hw, IIO_CHAN_INFO_FREQUENCY);
805827
}
806828

807829
static long hmc7044_clk_round_rate(struct clk_hw *hw,
@@ -811,11 +833,21 @@ static long hmc7044_clk_round_rate(struct clk_hw *hw,
811833
struct hmc7044_output *out = to_output(hw);
812834
struct iio_dev *indio_dev = out->indio_dev;
813835
struct hmc7044 *hmc = iio_priv(indio_dev);
836+
struct hmc7044_chan_spec *ch;
837+
long rounded_rate;
814838
unsigned int div;
815839

816-
div = hmc7044_calc_out_div(hmc->pll2_freq, rate);
840+
ch = &hmc->channels[out->address];
817841

818-
return DIV_ROUND_CLOSEST(hmc->pll2_freq, div);
842+
if (ch->num == 14) {
843+
div = hmc7044_calc_oscout_div(hmc->vcxo_freq, rate);
844+
rounded_rate = DIV_ROUND_CLOSEST(hmc->vcxo_freq, div);
845+
} else {
846+
div = hmc7044_calc_out_div(hmc->vcxo_freq, rate);
847+
rounded_rate = DIV_ROUND_CLOSEST(hmc->pll2_freq, div);
848+
}
849+
850+
return rounded_rate;
819851
}
820852

821853
static int hmc7044_clk_determine_rate(struct clk_hw *hw,
@@ -824,11 +856,20 @@ static int hmc7044_clk_determine_rate(struct clk_hw *hw,
824856
struct hmc7044_output *out = to_output(hw);
825857
struct iio_dev *indio_dev = out->indio_dev;
826858
struct hmc7044 *hmc = iio_priv(indio_dev);
859+
struct hmc7044_chan_spec *ch;
827860
unsigned int div;
828861

829-
div = hmc7044_calc_out_div(hmc->pll2_freq, req->rate);
862+
ch = &hmc->channels[out->address];
830863

831-
req->rate = DIV_ROUND_CLOSEST(hmc->pll2_freq, div);
864+
if (ch->num == 14) {
865+
div = hmc7044_calc_oscout_div(hmc->vcxo_freq, req->rate);
866+
867+
req->rate = DIV_ROUND_CLOSEST(hmc->vcxo_freq, div);
868+
} else {
869+
div = hmc7044_calc_out_div(hmc->pll2_freq, req->rate);
870+
871+
req->rate = DIV_ROUND_CLOSEST(hmc->pll2_freq, div);
872+
}
832873

833874
return 0;
834875
}
@@ -837,7 +878,25 @@ static int hmc7044_clk_set_rate(struct clk_hw *hw,
837878
unsigned long rate,
838879
unsigned long parent_rate)
839880
{
840-
return hmc7044_set_clk_attr(hw, IIO_CHAN_INFO_FREQUENCY, rate);
881+
struct hmc7044_output *out = to_output(hw);
882+
struct iio_dev *indio_dev = out->indio_dev;
883+
struct hmc7044 *hmc = iio_priv(indio_dev);
884+
struct hmc7044_chan_spec *ch;
885+
886+
ch = &hmc->channels[out->address];
887+
888+
if (ch->num == 14) {
889+
ch->divider = hmc7044_calc_oscout_div(hmc->vcxo_freq, rate);
890+
mutex_lock(&hmc->lock);
891+
hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_PATH,
892+
HMC7044_OSCOUT_DIVIDER(ch->divider <= 4 ? ch->divider / 2 : 3) |
893+
hmc->oscout_path_en);
894+
mutex_unlock(&hmc->lock);
895+
896+
return 0;
897+
} else {
898+
return hmc7044_set_clk_attr(hw, IIO_CHAN_INFO_FREQUENCY, rate);
899+
}
841900
}
842901

843902
static const struct clk_ops hmc7044_clk_ops = {
@@ -1057,6 +1116,12 @@ static int hmc7044_setup(struct iio_dev *indio_dev)
10571116
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
10581117
if (ret)
10591118
return ret;
1119+
1120+
if (i == 14) {
1121+
ret = hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_PATH, 0);
1122+
if (ret)
1123+
return ret;
1124+
}
10601125
}
10611126

10621127
/* Load the configuration updates (provided by Analog Devices) */
@@ -1264,52 +1329,84 @@ static int hmc7044_setup(struct iio_dev *indio_dev)
12641329
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
12651330
continue;
12661331

1267-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
1268-
HMC7044_DIV_LSB(chan->divider));
1269-
if (ret)
1270-
return ret;
1271-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
1272-
HMC7044_DIV_MSB(chan->divider));
1273-
if (ret)
1274-
return ret;
1275-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
1276-
HMC7044_DRIVER_MODE(chan->driver_mode) |
1277-
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
1278-
(chan->dynamic_driver_enable ?
1279-
HMC7044_DYN_DRIVER_EN : 0) |
1280-
(chan->force_mute_enable ?
1281-
HMC7044_FORCE_MUTE_EN : 0));
1282-
if (ret)
1283-
return ret;
1284-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
1285-
chan->fine_delay & 0x1F);
1286-
if (ret)
1287-
return ret;
1288-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
1289-
chan->coarse_delay & 0x1F);
1290-
if (ret)
1291-
return ret;
1292-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
1293-
chan->out_mux_mode & 0x3);
1294-
if (ret)
1295-
return ret;
1296-
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
1297-
(chan->start_up_mode_dynamic_enable ?
1298-
HMC7044_START_UP_MODE_DYN_EN : 0) | BIT(4) |
1299-
(chan->high_performance_mode_dis ?
1300-
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
1301-
HMC7044_CH_EN);
1302-
if (ret)
1303-
return ret;
1304-
hmc->iio_channels[i].type = IIO_ALTVOLTAGE;
1305-
hmc->iio_channels[i].output = 1;
1306-
hmc->iio_channels[i].indexed = 1;
1307-
hmc->iio_channels[i].channel = chan->num;
1308-
hmc->iio_channels[i].address = i;
1309-
hmc->iio_channels[i].extend_name = chan->extended_name;
1310-
hmc->iio_channels[i].info_mask_separate =
1311-
BIT(IIO_CHAN_INFO_FREQUENCY) |
1312-
BIT(IIO_CHAN_INFO_PHASE);
1332+
if (chan->num < (HMC7044_NUM_CHAN - 1)) {
1333+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
1334+
HMC7044_DIV_LSB(chan->divider));
1335+
if (ret)
1336+
return ret;
1337+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
1338+
HMC7044_DIV_MSB(chan->divider));
1339+
if (ret)
1340+
return ret;
1341+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
1342+
HMC7044_DRIVER_MODE(chan->driver_mode) |
1343+
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
1344+
(chan->dynamic_driver_enable ?
1345+
HMC7044_DYN_DRIVER_EN : 0) |
1346+
(chan->force_mute_enable ?
1347+
HMC7044_FORCE_MUTE_EN : 0));
1348+
if (ret)
1349+
return ret;
1350+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
1351+
chan->fine_delay & 0x1F);
1352+
if (ret)
1353+
return ret;
1354+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
1355+
chan->coarse_delay & 0x1F);
1356+
if (ret)
1357+
return ret;
1358+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
1359+
chan->out_mux_mode & 0x3);
1360+
if (ret)
1361+
return ret;
1362+
ret = hmc7044_write(indio_dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
1363+
(chan->start_up_mode_dynamic_enable ?
1364+
HMC7044_START_UP_MODE_DYN_EN : 0) | BIT(4) |
1365+
(chan->high_performance_mode_dis ?
1366+
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
1367+
HMC7044_CH_EN);
1368+
if (ret)
1369+
return ret;
1370+
hmc->iio_channels[i].type = IIO_ALTVOLTAGE;
1371+
hmc->iio_channels[i].output = 1;
1372+
hmc->iio_channels[i].indexed = 1;
1373+
hmc->iio_channels[i].channel = chan->num;
1374+
hmc->iio_channels[i].address = i;
1375+
hmc->iio_channels[i].extend_name = chan->extended_name;
1376+
hmc->iio_channels[i].info_mask_separate =
1377+
BIT(IIO_CHAN_INFO_FREQUENCY) |
1378+
BIT(IIO_CHAN_INFO_PHASE);
1379+
} else {
1380+
if (hmc->oscout_path_en) {
1381+
/* Make sure divider has acceptable value */
1382+
if (chan->divider != 1 && chan->divider != 2 &&
1383+
chan->divider != 4 && chan->divider != 8)
1384+
return -EINVAL;
1385+
ret = hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_PATH,
1386+
HMC7044_OSCOUT_DIVIDER(chan->divider <= 4 ? chan->divider / 2 : 3) |
1387+
HMC7044_CH_EN);
1388+
if (ret)
1389+
return ret;
1390+
}
1391+
1392+
if (hmc->oscout0_driver_en) {
1393+
hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_DRIVER_0,
1394+
HMC7044_OSCOUT_DRIVER_MODE(chan->driver_mode) |
1395+
HMC7044_OSCOUT_IMPEDANCE(chan->driver_impedance) |
1396+
HMC7044_CH_EN);
1397+
if (ret)
1398+
return ret;
1399+
}
1400+
1401+
if (hmc->oscout1_driver_en) {
1402+
hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_DRIVER_1,
1403+
HMC7044_OSCOUT_DRIVER_MODE(chan->driver_mode) |
1404+
HMC7044_OSCOUT_IMPEDANCE(chan->driver_impedance) |
1405+
HMC7044_CH_EN);
1406+
if (ret)
1407+
return ret;
1408+
}
1409+
}
13131410
}
13141411
mdelay(10);
13151412

@@ -1357,32 +1454,6 @@ static int hmc7044_setup(struct iio_dev *indio_dev)
13571454
hmc->clk_data.clks = hmc->clks;
13581455
hmc->clk_data.clk_num = HMC7044_NUM_CHAN;
13591456

1360-
if (hmc->oscout_path_en) {
1361-
ret = hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_PATH,
1362-
HMC7044_OSCOUT_DIVIDER(hmc->oscout_divider_ratio) |
1363-
hmc->oscout_path_en);
1364-
if (ret)
1365-
return ret;
1366-
}
1367-
1368-
if (hmc->oscout0_driver_en) {
1369-
hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_DRIVER_0,
1370-
HMC7044_OSCOUT_DRIVER_MODE(hmc->oscout1_driver_mode) |
1371-
HMC7044_OSCOUT_IMPEDANCE(hmc->oscout1_driver_impedance) |
1372-
hmc->oscout1_driver_en);
1373-
if (ret)
1374-
return ret;
1375-
}
1376-
1377-
if (hmc->oscout1_driver_en) {
1378-
hmc7044_write(indio_dev, HMC7044_REG_OSCOUT_DRIVER_1,
1379-
HMC7044_OSCOUT_DRIVER_MODE(hmc->oscout1_driver_mode) |
1380-
HMC7044_OSCOUT_IMPEDANCE(hmc->oscout1_driver_impedance) |
1381-
hmc->oscout1_driver_en);
1382-
if (ret)
1383-
return ret;
1384-
}
1385-
13861457
ret = hmc7044_info(indio_dev);
13871458
if (ret)
13881459
return ret;
@@ -1707,30 +1778,10 @@ static int hmc7044_parse_dt(struct device *dev,
17071778
hmc->oscout_path_en =
17081779
of_property_read_bool(np, "adi,oscillator-output-path-enable");
17091780

1710-
hmc->oscout_divider_ratio = HMC7044_DIVIDER_RATIO_1;
1711-
of_property_read_u32(np, "adi,oscillator-output-divider-ratio",
1712-
&hmc->oscout_divider_ratio);
1713-
17141781
hmc->oscout0_driver_en = of_property_read_bool(np, "adi,oscillator-output0-driver-enable");
17151782

1716-
hmc->oscout0_driver_mode = HMC7044_DRIVER_MODE_CML;
1717-
of_property_read_u32(np, "adi,oscillator-output0-driver-mode",
1718-
&hmc->oscout0_driver_mode);
1719-
1720-
hmc->oscout0_driver_impedance = HMC7044_DRIVER_IMPEDANCE_DISABLE;
1721-
of_property_read_u32(np, "adi,oscillator-output0-driver-impedance",
1722-
&hmc->oscout0_driver_impedance);
1723-
17241783
hmc->oscout1_driver_en = of_property_read_bool(np, "adi,oscillator-output1-driver-enable");
17251784

1726-
hmc->oscout1_driver_mode = HMC7044_DRIVER_MODE_CML;
1727-
of_property_read_u32(np, "adi,oscillator-output1-driver-mode",
1728-
&hmc->oscout1_driver_mode);
1729-
1730-
hmc->oscout1_driver_impedance = HMC7044_DRIVER_IMPEDANCE_DISABLE;
1731-
of_property_read_u32(np, "adi,oscillator-output1-driver-impedance",
1732-
&hmc->oscout1_driver_impedance);
1733-
17341785
hmc->sysref_timer_div = 256;
17351786
of_property_read_u32(np, "adi,sysref-timer-divider",
17361787
&hmc->sysref_timer_div);

0 commit comments

Comments
 (0)