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

ARM: OMAP2+: Allow using ti-sysc for system timers

If a system timer is configured with an interrconnect target module in
the dts, the ti,hwmods and module fck are at the interconnect target
level. Then there's a separate fck for the timer child device.

If the child device has a separate functional clock, we need to configure
it directly. For example, timer clk clkctrl clock bit 0 is the module
clock for the interconnect target, and bit 24 being the functional clock
for the timer IP.

For system timers, we already mark them as disabled. Now must also mark
the interconnect target module as disabled to prevent ti-sysc to manage
it instead of the system timer.

Cc: Keerthy <j-keerthy@ti.com>
Cc: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>

+52 -15
+52 -15
arch/arm/mach-omap2/timer.c
··· 167 167 { } 168 168 }; 169 169 170 + static int omap_timer_add_disabled_property(struct device_node *np) 171 + { 172 + struct property *prop; 173 + 174 + prop = kzalloc(sizeof(*prop), GFP_KERNEL); 175 + if (!prop) 176 + return -ENOMEM; 177 + 178 + prop->name = "status"; 179 + prop->value = "disabled"; 180 + prop->length = strlen(prop->value); 181 + 182 + return of_add_property(np, prop); 183 + } 184 + 185 + static int omap_timer_update_dt(struct device_node *np) 186 + { 187 + int error = 0; 188 + 189 + if (!of_device_is_compatible(np, "ti,omap-counter32k")) { 190 + error = omap_timer_add_disabled_property(np); 191 + if (error) 192 + return error; 193 + } 194 + 195 + /* No parent interconnect target module configured? */ 196 + if (of_get_property(np, "ti,hwmods", NULL)) 197 + return error; 198 + 199 + /* Tag parent interconnect target module disabled */ 200 + error = omap_timer_add_disabled_property(np->parent); 201 + if (error) 202 + return error; 203 + 204 + return 0; 205 + } 206 + 170 207 /** 171 208 * omap_get_timer_dt - get a timer using device-tree 172 209 * @match - device-tree match structure for matching a device type ··· 219 182 const char *property) 220 183 { 221 184 struct device_node *np; 185 + int error; 222 186 223 187 for_each_matching_node(np, match) { 224 188 if (!of_device_is_available(np)) ··· 234 196 of_get_property(np, "ti,timer-secure", NULL))) 235 197 continue; 236 198 237 - if (!of_device_is_compatible(np, "ti,omap-counter32k")) { 238 - struct property *prop; 199 + error = omap_timer_update_dt(np); 200 + WARN(error, "%s: Could not update dt: %i\n", __func__, error); 239 201 240 - prop = kzalloc(sizeof(*prop), GFP_KERNEL); 241 - if (!prop) 242 - return NULL; 243 - prop->name = "status"; 244 - prop->value = "disabled"; 245 - prop->length = strlen(prop->value); 246 - of_add_property(np, prop); 247 - } 248 202 return np; 249 203 } 250 204 ··· 295 265 return -ENODEV; 296 266 297 267 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); 298 - if (!oh_name) 299 - return -ENODEV; 268 + if (!oh_name) { 269 + of_property_read_string_index(np->parent, "ti,hwmods", 0, 270 + &oh_name); 271 + if (!oh_name) 272 + return -ENODEV; 273 + } 300 274 301 275 timer->irq = irq_of_parse_and_map(np, 0); 302 276 if (!timer->irq) ··· 452 418 if (!np) 453 419 return -ENODEV; 454 420 455 - of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); 456 - if (!oh_name) 457 - return -ENODEV; 421 + of_property_read_string_index(np->parent, "ti,hwmods", 0, &oh_name); 422 + if (!oh_name) { 423 + of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); 424 + if (!oh_name) 425 + return -ENODEV; 426 + } 458 427 459 428 /* 460 429 * First check hwmod data is available for sync32k counter