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

clocksource: sh_cmt: Add DT support

Document DT bindings and parse them in the CMT driver.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Simon Horman <horms+renesas@verge.net.au>

+95 -18
+47
Documentation/devicetree/bindings/timer/renesas,cmt.txt
··· 1 + * Renesas R-Car Compare Match Timer (CMT) 2 + 3 + The CMT is a multi-channel 16/32/48-bit timer/counter with configurable clock 4 + inputs and programmable compare match. 5 + 6 + Channels share hardware resources but their counter and compare match value 7 + are independent. A particular CMT instance can implement only a subset of the 8 + channels supported by the CMT model. Channel indices represent the hardware 9 + position of the channel in the CMT and don't match the channel numbers in the 10 + datasheets. 11 + 12 + Required Properties: 13 + 14 + - compatible: must contain one of the following. 15 + - "renesas,cmt-32" for the 32-bit CMT 16 + (CMT0 on sh7372, sh73a0 and r8a7740) 17 + - "renesas,cmt-32-fast" for the 32-bit CMT with fast clock support 18 + (CMT[234] on sh7372, sh73a0 and r8a7740) 19 + - "renesas,cmt-48" for the 48-bit CMT 20 + (CMT1 on sh7372, sh73a0 and r8a7740) 21 + - "renesas,cmt-48-gen2" for the second generation 48-bit CMT 22 + (CMT[01] on r8a73a4, r8a7790 and r8a7791) 23 + 24 + - reg: base address and length of the registers block for the timer module. 25 + - interrupts: interrupt-specifier for the timer, one per channel. 26 + - clocks: a list of phandle + clock-specifier pairs, one for each entry 27 + in clock-names. 28 + - clock-names: must contain "fck" for the functional clock. 29 + 30 + - renesas,channels-mask: bitmask of the available channels. 31 + 32 + 33 + Example: R8A7790 (R-Car H2) CMT0 node 34 + 35 + CMT0 on R8A7790 implements hardware channels 5 and 6 only and names 36 + them channels 0 and 1 in the documentation. 37 + 38 + cmt0: timer@ffca0000 { 39 + compatible = "renesas,cmt-48-gen2"; 40 + reg = <0 0xffca0000 0 0x1004>; 41 + interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>, 42 + <0 142 IRQ_TYPE_LEVEL_HIGH>; 43 + clocks = <&mstp1_clks R8A7790_CLK_CMT0>; 44 + clock-names = "fck"; 45 + 46 + renesas,channels-mask = <0x60>; 47 + };
+48 -18
drivers/clocksource/sh_cmt.c
··· 24 24 #include <linux/ioport.h> 25 25 #include <linux/irq.h> 26 26 #include <linux/module.h> 27 + #include <linux/of.h> 27 28 #include <linux/platform_device.h> 28 29 #include <linux/pm_domain.h> 29 30 #include <linux/pm_runtime.h> ··· 123 122 124 123 struct sh_cmt_channel *channels; 125 124 unsigned int num_channels; 125 + unsigned int hw_channels; 126 126 127 127 bool has_clockevent; 128 128 bool has_clocksource; ··· 926 924 return 0; 927 925 } 928 926 927 + static const struct platform_device_id sh_cmt_id_table[] = { 928 + { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, 929 + { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, 930 + { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, 931 + { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, 932 + { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, 933 + { } 934 + }; 935 + MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); 936 + 937 + static const struct of_device_id sh_cmt_of_table[] __maybe_unused = { 938 + { .compatible = "renesas,cmt-32", .data = &sh_cmt_info[SH_CMT_32BIT] }, 939 + { .compatible = "renesas,cmt-32-fast", .data = &sh_cmt_info[SH_CMT_32BIT_FAST] }, 940 + { .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] }, 941 + { .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT_48BIT_GEN2] }, 942 + { } 943 + }; 944 + MODULE_DEVICE_TABLE(of, sh_cmt_of_table); 945 + 946 + static int sh_cmt_parse_dt(struct sh_cmt_device *cmt) 947 + { 948 + struct device_node *np = cmt->pdev->dev.of_node; 949 + 950 + return of_property_read_u32(np, "renesas,channels-mask", 951 + &cmt->hw_channels); 952 + } 953 + 929 954 static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) 930 955 { 931 - struct sh_timer_config *cfg = pdev->dev.platform_data; 932 - const struct platform_device_id *id = pdev->id_entry; 933 956 unsigned int mask; 934 957 unsigned int i; 935 958 int ret; ··· 963 936 cmt->pdev = pdev; 964 937 raw_spin_lock_init(&cmt->lock); 965 938 966 - if (!cfg) { 939 + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { 940 + const struct of_device_id *id; 941 + 942 + id = of_match_node(sh_cmt_of_table, pdev->dev.of_node); 943 + cmt->info = id->data; 944 + 945 + ret = sh_cmt_parse_dt(cmt); 946 + if (ret < 0) 947 + return ret; 948 + } else if (pdev->dev.platform_data) { 949 + struct sh_timer_config *cfg = pdev->dev.platform_data; 950 + const struct platform_device_id *id = pdev->id_entry; 951 + 952 + cmt->info = (const struct sh_cmt_info *)id->driver_data; 953 + cmt->hw_channels = cfg->channels_mask; 954 + } else { 967 955 dev_err(&cmt->pdev->dev, "missing platform data\n"); 968 956 return -ENXIO; 969 957 } 970 - 971 - cmt->info = (const struct sh_cmt_info *)id->driver_data; 972 958 973 959 /* Get hold of clock. */ 974 960 cmt->clk = clk_get(&cmt->pdev->dev, "fck"); ··· 1000 960 goto err_clk_unprepare; 1001 961 1002 962 /* Allocate and setup the channels. */ 1003 - cmt->num_channels = hweight8(cfg->channels_mask); 1004 - 963 + cmt->num_channels = hweight8(cmt->hw_channels); 1005 964 cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), 1006 965 GFP_KERNEL); 1007 966 if (cmt->channels == NULL) { ··· 1012 973 * Use the first channel as a clock event device and the second channel 1013 974 * as a clock source. If only one channel is available use it for both. 1014 975 */ 1015 - for (i = 0, mask = cfg->channels_mask; i < cmt->num_channels; ++i) { 976 + for (i = 0, mask = cmt->hw_channels; i < cmt->num_channels; ++i) { 1016 977 unsigned int hwidx = ffs(mask) - 1; 1017 978 bool clocksource = i == 1 || cmt->num_channels == 1; 1018 979 bool clockevent = i == 0; ··· 1081 1042 return -EBUSY; /* cannot unregister clockevent and clocksource */ 1082 1043 } 1083 1044 1084 - static const struct platform_device_id sh_cmt_id_table[] = { 1085 - { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, 1086 - { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, 1087 - { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, 1088 - { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, 1089 - { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, 1090 - { } 1091 - }; 1092 - MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); 1093 - 1094 1045 static struct platform_driver sh_cmt_device_driver = { 1095 1046 .probe = sh_cmt_probe, 1096 1047 .remove = sh_cmt_remove, 1097 1048 .driver = { 1098 1049 .name = "sh_cmt", 1050 + .of_match_table = of_match_ptr(sh_cmt_of_table), 1099 1051 }, 1100 1052 .id_table = sh_cmt_id_table, 1101 1053 };