Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: frequency: adf4377: add clk provider support

Add clk provider feature for the adf4377.

Even though the driver was sent as an IIO driver in most cases the
device is actually seen as a clock provider.

This patch aims to cover actual usecases requested by users in order to
completely control the output frequencies from userspace.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Antoniu Miclaus and committed by
Jonathan Cameron
60e5448d d4f13bc9

+120 -2
+120 -2
drivers/iio/frequency/adf4377.c
··· 8 8 #include <linux/bitfield.h> 9 9 #include <linux/bits.h> 10 10 #include <linux/clk.h> 11 + #include <linux/clk-provider.h> 11 12 #include <linux/clkdev.h> 13 + #include <linux/container_of.h> 12 14 #include <linux/delay.h> 13 15 #include <linux/device.h> 14 16 #include <linux/gpio/consumer.h> ··· 437 435 struct gpio_desc *gpio_ce; 438 436 struct gpio_desc *gpio_enclk1; 439 437 struct gpio_desc *gpio_enclk2; 438 + struct clk *clk; 439 + struct clk *clkout; 440 + struct clk_hw hw; 440 441 u8 buf[2] __aligned(IIO_DMA_MINALIGN); 441 442 }; 443 + 444 + #define to_adf4377_state(h) container_of(h, struct adf4377_state, hw) 442 445 443 446 static const char * const adf4377_muxout_modes[] = { 444 447 [ADF4377_MUXOUT_HIGH_Z] = "high_z", ··· 936 929 return NOTIFY_OK; 937 930 } 938 931 932 + static unsigned long adf4377_clk_recalc_rate(struct clk_hw *hw, 933 + unsigned long parent_rate) 934 + { 935 + struct adf4377_state *st = to_adf4377_state(hw); 936 + u64 freq; 937 + int ret; 938 + 939 + ret = adf4377_get_freq(st, &freq); 940 + if (ret) 941 + return 0; 942 + 943 + return freq; 944 + } 945 + 946 + static int adf4377_clk_set_rate(struct clk_hw *hw, 947 + unsigned long rate, 948 + unsigned long parent_rate) 949 + { 950 + struct adf4377_state *st = to_adf4377_state(hw); 951 + 952 + return adf4377_set_freq(st, rate); 953 + } 954 + 955 + static int adf4377_clk_prepare(struct clk_hw *hw) 956 + { 957 + struct adf4377_state *st = to_adf4377_state(hw); 958 + 959 + return regmap_update_bits(st->regmap, 0x1a, ADF4377_001A_PD_CLKOUT1_MSK | 960 + ADF4377_001A_PD_CLKOUT2_MSK, 961 + FIELD_PREP(ADF4377_001A_PD_CLKOUT1_MSK, 0) | 962 + FIELD_PREP(ADF4377_001A_PD_CLKOUT2_MSK, 0)); 963 + } 964 + 965 + static void adf4377_clk_unprepare(struct clk_hw *hw) 966 + { 967 + struct adf4377_state *st = to_adf4377_state(hw); 968 + 969 + regmap_update_bits(st->regmap, 0x1a, ADF4377_001A_PD_CLKOUT1_MSK | 970 + ADF4377_001A_PD_CLKOUT2_MSK, 971 + FIELD_PREP(ADF4377_001A_PD_CLKOUT1_MSK, 1) | 972 + FIELD_PREP(ADF4377_001A_PD_CLKOUT2_MSK, 1)); 973 + } 974 + 975 + static int adf4377_clk_is_prepared(struct clk_hw *hw) 976 + { 977 + struct adf4377_state *st = to_adf4377_state(hw); 978 + unsigned int readval; 979 + int ret; 980 + 981 + ret = regmap_read(st->regmap, 0x1a, &readval); 982 + if (ret) 983 + return ret; 984 + 985 + return !(readval & (ADF4377_001A_PD_CLKOUT1_MSK | ADF4377_001A_PD_CLKOUT2_MSK)); 986 + } 987 + 988 + static const struct clk_ops adf4377_clk_ops = { 989 + .recalc_rate = adf4377_clk_recalc_rate, 990 + .set_rate = adf4377_clk_set_rate, 991 + .prepare = adf4377_clk_prepare, 992 + .unprepare = adf4377_clk_unprepare, 993 + .is_prepared = adf4377_clk_is_prepared, 994 + }; 995 + 996 + static int adf4377_clk_register(struct adf4377_state *st) 997 + { 998 + struct spi_device *spi = st->spi; 999 + struct device *dev = &spi->dev; 1000 + struct clk_init_data init; 1001 + struct clk_parent_data parent_data; 1002 + int ret; 1003 + 1004 + if (!device_property_present(dev, "#clock-cells")) 1005 + return 0; 1006 + 1007 + ret = device_property_read_string(dev, "clock-output-names", &init.name); 1008 + if (ret) { 1009 + init.name = devm_kasprintf(dev, GFP_KERNEL, "%pfw-clk", 1010 + dev_fwnode(dev)); 1011 + if (!init.name) 1012 + return -ENOMEM; 1013 + } 1014 + 1015 + parent_data.fw_name = "ref_in"; 1016 + 1017 + init.ops = &adf4377_clk_ops; 1018 + init.parent_data = &parent_data; 1019 + init.num_parents = 1; 1020 + init.flags = CLK_SET_RATE_PARENT; 1021 + 1022 + st->hw.init = &init; 1023 + ret = devm_clk_hw_register(dev, &st->hw); 1024 + if (ret) 1025 + return ret; 1026 + 1027 + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &st->hw); 1028 + if (ret) 1029 + return ret; 1030 + 1031 + st->clkout = st->hw.clk; 1032 + 1033 + return 0; 1034 + } 1035 + 939 1036 static const struct adf4377_chip_info adf4377_chip_info = { 940 1037 .name = "adf4377", 941 1038 .has_gpio_enclk2 = true, ··· 1069 958 1070 959 indio_dev->info = &adf4377_info; 1071 960 indio_dev->name = "adf4377"; 1072 - indio_dev->channels = adf4377_channels; 1073 - indio_dev->num_channels = ARRAY_SIZE(adf4377_channels); 1074 961 1075 962 st->regmap = regmap; 1076 963 st->spi = spi; ··· 1087 978 ret = adf4377_init(st); 1088 979 if (ret) 1089 980 return ret; 981 + 982 + ret = adf4377_clk_register(st); 983 + if (ret) 984 + return ret; 985 + 986 + if (!st->clkout) { 987 + indio_dev->channels = adf4377_channels; 988 + indio_dev->num_channels = ARRAY_SIZE(adf4377_channels); 989 + } 1090 990 1091 991 return devm_iio_device_register(&spi->dev, indio_dev); 1092 992 }