···11+* Renesas R-Car Compare Match Timer (CMT)22+33+The CMT is a multi-channel 16/32/48-bit timer/counter with configurable clock44+inputs and programmable compare match.55+66+Channels share hardware resources but their counter and compare match value77+are independent. A particular CMT instance can implement only a subset of the88+channels supported by the CMT model. Channel indices represent the hardware99+position of the channel in the CMT and don't match the channel numbers in the1010+datasheets.1111+1212+Required Properties:1313+1414+ - compatible: must contain one of the following.1515+ - "renesas,cmt-32" for the 32-bit CMT1616+ (CMT0 on sh7372, sh73a0 and r8a7740)1717+ - "renesas,cmt-32-fast" for the 32-bit CMT with fast clock support1818+ (CMT[234] on sh7372, sh73a0 and r8a7740)1919+ - "renesas,cmt-48" for the 48-bit CMT2020+ (CMT1 on sh7372, sh73a0 and r8a7740)2121+ - "renesas,cmt-48-gen2" for the second generation 48-bit CMT2222+ (CMT[01] on r8a73a4, r8a7790 and r8a7791)2323+2424+ - reg: base address and length of the registers block for the timer module.2525+ - interrupts: interrupt-specifier for the timer, one per channel.2626+ - clocks: a list of phandle + clock-specifier pairs, one for each entry2727+ in clock-names.2828+ - clock-names: must contain "fck" for the functional clock.2929+3030+ - renesas,channels-mask: bitmask of the available channels.3131+3232+3333+Example: R8A7790 (R-Car H2) CMT0 node3434+3535+ CMT0 on R8A7790 implements hardware channels 5 and 6 only and names3636+ them channels 0 and 1 in the documentation.3737+3838+ cmt0: timer@ffca0000 {3939+ compatible = "renesas,cmt-48-gen2";4040+ reg = <0 0xffca0000 0 0x1004>;4141+ interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>,4242+ <0 142 IRQ_TYPE_LEVEL_HIGH>;4343+ clocks = <&mstp1_clks R8A7790_CLK_CMT0>;4444+ clock-names = "fck";4545+4646+ renesas,channels-mask = <0x60>;4747+ };
+48-18
drivers/clocksource/sh_cmt.c
···2424#include <linux/ioport.h>2525#include <linux/irq.h>2626#include <linux/module.h>2727+#include <linux/of.h>2728#include <linux/platform_device.h>2829#include <linux/pm_domain.h>2930#include <linux/pm_runtime.h>···123122124123 struct sh_cmt_channel *channels;125124 unsigned int num_channels;125125+ unsigned int hw_channels;126126127127 bool has_clockevent;128128 bool has_clocksource;···926924 return 0;927925}928926927927+static const struct platform_device_id sh_cmt_id_table[] = {928928+ { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] },929929+ { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] },930930+ { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] },931931+ { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] },932932+ { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] },933933+ { }934934+};935935+MODULE_DEVICE_TABLE(platform, sh_cmt_id_table);936936+937937+static const struct of_device_id sh_cmt_of_table[] __maybe_unused = {938938+ { .compatible = "renesas,cmt-32", .data = &sh_cmt_info[SH_CMT_32BIT] },939939+ { .compatible = "renesas,cmt-32-fast", .data = &sh_cmt_info[SH_CMT_32BIT_FAST] },940940+ { .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] },941941+ { .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT_48BIT_GEN2] },942942+ { }943943+};944944+MODULE_DEVICE_TABLE(of, sh_cmt_of_table);945945+946946+static int sh_cmt_parse_dt(struct sh_cmt_device *cmt)947947+{948948+ struct device_node *np = cmt->pdev->dev.of_node;949949+950950+ return of_property_read_u32(np, "renesas,channels-mask",951951+ &cmt->hw_channels);952952+}953953+929954static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)930955{931931- struct sh_timer_config *cfg = pdev->dev.platform_data;932932- const struct platform_device_id *id = pdev->id_entry;933956 unsigned int mask;934957 unsigned int i;935958 int ret;···963936 cmt->pdev = pdev;964937 raw_spin_lock_init(&cmt->lock);965938966966- if (!cfg) {939939+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {940940+ const struct of_device_id *id;941941+942942+ id = of_match_node(sh_cmt_of_table, pdev->dev.of_node);943943+ cmt->info = id->data;944944+945945+ ret = sh_cmt_parse_dt(cmt);946946+ if (ret < 0)947947+ return ret;948948+ } else if (pdev->dev.platform_data) {949949+ struct sh_timer_config *cfg = pdev->dev.platform_data;950950+ const struct platform_device_id *id = pdev->id_entry;951951+952952+ cmt->info = (const struct sh_cmt_info *)id->driver_data;953953+ cmt->hw_channels = cfg->channels_mask;954954+ } else {967955 dev_err(&cmt->pdev->dev, "missing platform data\n");968956 return -ENXIO;969957 }970970-971971- cmt->info = (const struct sh_cmt_info *)id->driver_data;972958973959 /* Get hold of clock. */974960 cmt->clk = clk_get(&cmt->pdev->dev, "fck");···1000960 goto err_clk_unprepare;10019611002962 /* Allocate and setup the channels. */10031003- cmt->num_channels = hweight8(cfg->channels_mask);10041004-963963+ cmt->num_channels = hweight8(cmt->hw_channels);1005964 cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels),1006965 GFP_KERNEL);1007966 if (cmt->channels == NULL) {···1012973 * Use the first channel as a clock event device and the second channel1013974 * as a clock source. If only one channel is available use it for both.1014975 */10151015- for (i = 0, mask = cfg->channels_mask; i < cmt->num_channels; ++i) {976976+ for (i = 0, mask = cmt->hw_channels; i < cmt->num_channels; ++i) {1016977 unsigned int hwidx = ffs(mask) - 1;1017978 bool clocksource = i == 1 || cmt->num_channels == 1;1018979 bool clockevent = i == 0;···10811042 return -EBUSY; /* cannot unregister clockevent and clocksource */10821043}1083104410841084-static const struct platform_device_id sh_cmt_id_table[] = {10851085- { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] },10861086- { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] },10871087- { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] },10881088- { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] },10891089- { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] },10901090- { }10911091-};10921092-MODULE_DEVICE_TABLE(platform, sh_cmt_id_table);10931093-10941045static struct platform_driver sh_cmt_device_driver = {10951046 .probe = sh_cmt_probe,10961047 .remove = sh_cmt_remove,10971048 .driver = {10981049 .name = "sh_cmt",10501050+ .of_match_table = of_match_ptr(sh_cmt_of_table),10991051 },11001052 .id_table = sh_cmt_id_table,11011053};