Skip to content

Commit 3019403

Browse files
committed
iio: jesd204: axi_adxcvr: use managed resource in probe
Make use of devm_* variants and devm_add_action_or_reset() for automatically release the resources allocated in probe. Hence the driver .remove() hook can be removed. The goal was to keep the same order when releasing the resource as we had with the .remove() hook. Also note the move to the advised devm_clk_hw_register() so that we can also make use of devm_of_clk_add_hw_provider(). Additional care was needed when the jesd204 FSM is only started from a worker thread. In that case, we need to sync the worker (so we're sure it ran) and cache the return from jesd204_fsm_start() so that we only stop the state machine if successfully started. Signed-off-by: Nuno Sa <[email protected]>
1 parent bc20f2f commit 3019403

File tree

2 files changed

+98
-83
lines changed

2 files changed

+98
-83
lines changed

drivers/iio/jesd204/axi_adxcvr.c

+96-81
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ static int adxcvr_clk_register(struct device *dev,
757757
{
758758
struct adxcvr_state *st = dev_get_drvdata(dev);
759759
unsigned int out_clk_divider, out_clk_multiplier;
760+
struct clk_hw *fixed_factor;
760761
struct clk_init_data init;
761762
const char *clk_names[3];
762763
unsigned int num_clks;
@@ -784,13 +785,18 @@ static int adxcvr_clk_register(struct device *dev,
784785
st->lane_clk_hw.init = &init;
785786

786787
/* register the clock */
787-
st->clks[0] = devm_clk_register(dev, &st->lane_clk_hw);
788-
if (IS_ERR(st->clks[0]))
789-
return PTR_ERR(st->clks[0]);
788+
ret = devm_clk_hw_register(dev, &st->lane_clk_hw);
789+
if (ret)
790+
return ret;
790791

791792
/* Backwards compatibility */
792793
if (num_clks == 1)
793-
return of_clk_add_provider(node, of_clk_src_simple_get, st->clks[0]);
794+
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &st->lane_clk_hw);
795+
796+
st->clk_lookup = devm_kzalloc(dev, struct_size(st->clk_lookup, hws, num_clks),
797+
GFP_KERNEL);
798+
if (!st->clk_lookup)
799+
return -ENOMEM;
794800

795801
if (num_clks == 3) {
796802
init.name = clk_names[2];
@@ -803,9 +809,11 @@ static int adxcvr_clk_register(struct device *dev,
803809
st->qpll_clk_hw.init = &init;
804810

805811
/* register the clock */
806-
st->clks[2] = devm_clk_register(dev, &st->qpll_clk_hw);
807-
if (IS_ERR(st->clks[2]))
808-
return PTR_ERR(st->clks[2]);
812+
ret = devm_clk_hw_register(dev, &st->qpll_clk_hw);
813+
if (ret)
814+
return ret;
815+
816+
st->clk_lookup->hws[2] = &st->qpll_clk_hw;
809817
}
810818

811819
switch (st->out_clk_sel) {
@@ -847,19 +855,16 @@ static int adxcvr_clk_register(struct device *dev,
847855
return 0;
848856
}
849857

850-
st->clks[1] = clk_register_fixed_factor(dev, clk_names[1],
851-
parent_name, 0, out_clk_multiplier, out_clk_divider);
852-
853-
st->clk_lookup.clks = st->clks;
854-
st->clk_lookup.clk_num = ARRAY_SIZE(st->clks);
858+
fixed_factor = devm_clk_hw_register_fixed_factor(dev, clk_names[1], parent_name, 0,
859+
out_clk_multiplier, out_clk_divider);
860+
if (IS_ERR(fixed_factor))
861+
return PTR_ERR(fixed_factor);
855862

856-
ret = of_clk_add_provider(node, of_clk_src_onecell_get,
857-
&st->clk_lookup);
858-
859-
if (ret)
860-
clk_unregister_fixed_factor(st->clks[1]);
863+
st->clk_lookup->hws[0] = &st->lane_clk_hw;
864+
st->clk_lookup->hws[1] = fixed_factor;
865+
st->clk_lookup->num = num_clks;
861866

862-
return ret;
867+
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, st->clk_lookup);
863868
}
864869

865870
static void adxcvr_parse_dt_vco_ranges(struct adxcvr_state *st,
@@ -974,6 +979,21 @@ static const char *adxcvr_gt_names[] = {
974979
static const struct jesd204_dev_data adxcvr_jesd204_data = {
975980
};
976981

982+
static void adxcvr_clock_disable(void *clk)
983+
{
984+
clk_disable_unprepare(clk);
985+
}
986+
987+
static void adxvcr_lane_rate_disable(void *data)
988+
{
989+
struct adxcvr_state *st = data;
990+
991+
/* sync up the worker */
992+
cancel_work_sync(&st->work);
993+
if (__clk_is_enabled(st->lane_rate_div40_clk))
994+
clk_disable_unprepare(st->lane_rate_div40_clk);
995+
}
996+
977997
static void adxcvr_device_remove_files(void *data)
978998
{
979999
struct adxcvr_state *st = data;
@@ -992,12 +1012,31 @@ static void adxcvr_device_remove_files(void *data)
9921012
device_remove_file(st->dev, &dev_attr_reg_access);
9931013
}
9941014

1015+
static void adxcvr_unregister_eyescan(void *st)
1016+
{
1017+
adxcvr_eyescan_unregister(st);
1018+
}
1019+
9951020
static void adxcvr_fsm_en_work(struct work_struct *work)
9961021
{
9971022
struct adxcvr_state *st =
9981023
container_of(work, struct adxcvr_state, jesd_fsm_en_work.work);
9991024

1000-
jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL);
1025+
st->fsm_start_delayed_ret = jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL);
1026+
}
1027+
1028+
static void adxvcr_jesd204_fsm_stop(void *data)
1029+
{
1030+
struct adxcvr_state *st = data;
1031+
1032+
/* unlikely but just in case... */
1033+
if (st->fsm_enable_delay_ms)
1034+
cancel_delayed_work_sync(&st->jesd_fsm_en_work);
1035+
1036+
if (st->fsm_start_delayed_ret)
1037+
return;
1038+
1039+
jesd204_fsm_stop(st->jdev, JESD204_LINKS_ALL);
10011040
}
10021041

10031042
static int adxcvr_probe(struct platform_device *pdev)
@@ -1015,7 +1054,7 @@ static int adxcvr_probe(struct platform_device *pdev)
10151054
if (IS_ERR(st->jdev))
10161055
return PTR_ERR(st->jdev);
10171056

1018-
st->conv_clk = devm_clk_get(&pdev->dev, "conv");
1057+
st->conv_clk = devm_clk_get_enabled(&pdev->dev, "conv");
10191058
if (IS_ERR(st->conv_clk))
10201059
return PTR_ERR(st->conv_clk);
10211060

@@ -1044,14 +1083,15 @@ static int adxcvr_probe(struct platform_device *pdev)
10441083
st->lane_rate_div40_clk = ERR_PTR(-ENOENT);
10451084
}
10461085

1047-
ret = clk_prepare_enable(st->conv_clk);
1048-
if (ret < 0)
1049-
return ret;
1050-
10511086
if (st->conv2_clk) {
10521087
ret = clk_prepare_enable(st->conv2_clk);
10531088
if (ret)
1054-
goto disable_unprepare_conv_clk;
1089+
return ret;
1090+
1091+
ret = devm_add_action_or_reset(&pdev->dev, adxcvr_clock_disable,
1092+
st->conv2_clk);
1093+
if (ret)
1094+
return ret;
10551095
}
10561096

10571097
st->xcvr.dev = &pdev->dev;
@@ -1067,7 +1107,7 @@ static int adxcvr_probe(struct platform_device *pdev)
10671107
st->regs = devm_platform_ioremap_resource(pdev, 0);
10681108
if (IS_ERR(st->regs)) {
10691109
ret = PTR_ERR(st->regs);
1070-
goto disable_unprepare_conv_clk2;
1110+
return ret;
10711111
}
10721112

10731113
st->dev = &pdev->dev;
@@ -1100,8 +1140,7 @@ static int adxcvr_probe(struct platform_device *pdev)
11001140
break;
11011141
default:
11021142
pr_err("axi_adxcvr: not supported\n");
1103-
ret = -EINVAL;
1104-
goto disable_unprepare_conv_clk2;
1143+
return -EINVAL;
11051144
}
11061145
} else
11071146
st->xcvr.type = xcvr_type;
@@ -1115,8 +1154,7 @@ static int adxcvr_probe(struct platform_device *pdev)
11151154
default:
11161155
dev_err(&pdev->dev, "Unknown transceiver type: %d\n",
11171156
st->xcvr.type);
1118-
ret = -EINVAL;
1119-
goto disable_unprepare_conv_clk2;
1157+
return -EINVAL;
11201158
}
11211159

11221160
st->xcvr.encoding = ENC_8B10B;
@@ -1146,11 +1184,15 @@ static int adxcvr_probe(struct platform_device *pdev)
11461184

11471185
ret = adxcvr_clk_register(&pdev->dev, np, __clk_get_name(st->conv_clk));
11481186
if (ret)
1149-
goto disable_unprepare_conv_clk2;
1187+
return ret;
11501188

11511189
ret = adxcvr_eyescan_register(st);
11521190
if (ret)
1153-
goto unreg_adxcvr_clk;
1191+
return ret;
1192+
1193+
ret = devm_add_action_or_reset(&pdev->dev, adxcvr_unregister_eyescan, st);
1194+
if (ret)
1195+
return ret;
11541196

11551197
device_create_file(st->dev, &dev_attr_reg_access);
11561198

@@ -1166,16 +1208,30 @@ static int adxcvr_probe(struct platform_device *pdev)
11661208
}
11671209
}
11681210

1169-
devm_add_action_or_reset(st->dev, adxcvr_device_remove_files, st);
1211+
ret = devm_add_action_or_reset(st->dev, adxcvr_device_remove_files, st);
1212+
if (ret)
1213+
return ret;
11701214

1171-
if (st->fsm_enable_delay_ms) {
1172-
INIT_DELAYED_WORK(&st->jesd_fsm_en_work, adxcvr_fsm_en_work);
1173-
schedule_delayed_work(&st->jesd_fsm_en_work,
1174-
msecs_to_jiffies(st->fsm_enable_delay_ms));
1175-
} else {
1176-
ret = jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL);
1215+
if (st->jdev) {
1216+
if (st->fsm_enable_delay_ms) {
1217+
INIT_DELAYED_WORK(&st->jesd_fsm_en_work, adxcvr_fsm_en_work);
1218+
schedule_delayed_work(&st->jesd_fsm_en_work,
1219+
msecs_to_jiffies(st->fsm_enable_delay_ms));
1220+
} else {
1221+
ret = jesd204_fsm_start(st->jdev, JESD204_LINKS_ALL);
1222+
if (ret)
1223+
return ret;
1224+
}
1225+
1226+
ret = devm_add_action_or_reset(&pdev->dev, adxvcr_jesd204_fsm_stop, st);
11771227
if (ret)
1178-
goto unreg_eyescan;
1228+
return ret;
1229+
}
1230+
1231+
if (!IS_ERR(st->lane_rate_div40_clk)) {
1232+
ret = devm_add_action_or_reset(&pdev->dev, adxvcr_lane_rate_disable, st);
1233+
if (ret)
1234+
return ret;
11791235
}
11801236

11811237
dev_info(&pdev->dev, "AXI-ADXCVR-%s (%d.%.2d.%c) using %s on %s. Number of lanes: %d.",
@@ -1186,55 +1242,14 @@ static int adxcvr_probe(struct platform_device *pdev)
11861242
st->num_lanes);
11871243

11881244
return 0;
1189-
1190-
unreg_eyescan:
1191-
adxcvr_eyescan_unregister(st);
1192-
unreg_adxcvr_clk:
1193-
if (st->clks[1])
1194-
clk_unregister_fixed_factor(st->clks[1]);
1195-
of_clk_del_provider(pdev->dev.of_node);
1196-
disable_unprepare_conv_clk2:
1197-
clk_disable_unprepare(st->conv2_clk);
1198-
disable_unprepare_conv_clk:
1199-
clk_disable_unprepare(st->conv_clk);
1200-
1201-
return ret;
1202-
}
1203-
1204-
/**
1205-
* adxcvr_remove - unbinds the driver from the AIM device.
1206-
* @of_dev: pointer to OF device structure
1207-
*
1208-
* This function is called if a device is physically removed from the system or
1209-
* if the driver module is being unloaded. It frees any resources allocated to
1210-
* the device.
1211-
*/
1212-
static int adxcvr_remove(struct platform_device *pdev)
1213-
{
1214-
struct adxcvr_state *st = platform_get_drvdata(pdev);
1215-
1216-
/* sync up the worker */
1217-
cancel_work_sync(&st->work);
1218-
if (!IS_ERR(st->lane_rate_div40_clk) && __clk_is_enabled(st->lane_rate_div40_clk))
1219-
clk_disable_unprepare(st->lane_rate_div40_clk);
1220-
adxcvr_eyescan_unregister(st);
1221-
if (st->clks[1])
1222-
clk_unregister_fixed_factor(st->clks[1]);
1223-
of_clk_del_provider(pdev->dev.of_node);
1224-
clk_disable_unprepare(st->conv2_clk);
1225-
clk_disable_unprepare(st->conv_clk);
1226-
1227-
return 0;
12281245
}
12291246

12301247
static struct platform_driver adxcvr_of_driver = {
12311248
.driver = {
12321249
.name = KBUILD_MODNAME,
1233-
.owner = THIS_MODULE,
12341250
.of_match_table = adxcvr_of_match,
12351251
},
12361252
.probe = adxcvr_probe,
1237-
.remove = adxcvr_remove,
12381253
};
12391254

12401255
module_platform_driver(adxcvr_of_driver);

drivers/iio/jesd204/axi_adxcvr.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ struct adxcvr_state {
7878
u32 sys_clk_sel;
7979
u32 out_clk_sel;
8080
u32 fsm_enable_delay_ms;
81+
int fsm_start_delayed_ret;
8182

82-
struct clk *clks[3];
83-
struct clk_onecell_data clk_lookup;
83+
struct clk_hw_onecell_data *clk_lookup;
8484

8585
struct xilinx_xcvr xcvr;
8686
struct adxcvr_eyescan *eye;

0 commit comments

Comments
 (0)