19ac33b0cSPeter Ujfalusi /* 29ac33b0cSPeter Ujfalusi * DRA7 ATL (Audio Tracking Logic) clock driver 39ac33b0cSPeter Ujfalusi * 49ac33b0cSPeter Ujfalusi * Copyright (C) 2013 Texas Instruments, Inc. 59ac33b0cSPeter Ujfalusi * 69ac33b0cSPeter Ujfalusi * Peter Ujfalusi <peter.ujfalusi@ti.com> 79ac33b0cSPeter Ujfalusi * 89ac33b0cSPeter Ujfalusi * This program is free software; you can redistribute it and/or modify 99ac33b0cSPeter Ujfalusi * it under the terms of the GNU General Public License version 2 as 109ac33b0cSPeter Ujfalusi * published by the Free Software Foundation. 119ac33b0cSPeter Ujfalusi * 129ac33b0cSPeter Ujfalusi * This program is distributed "as is" WITHOUT ANY WARRANTY of any 139ac33b0cSPeter Ujfalusi * kind, whether express or implied; without even the implied warranty 149ac33b0cSPeter Ujfalusi * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159ac33b0cSPeter Ujfalusi * GNU General Public License for more details. 169ac33b0cSPeter Ujfalusi */ 179ac33b0cSPeter Ujfalusi 189ac33b0cSPeter Ujfalusi #include <linux/module.h> 191b29e601SStephen Boyd #include <linux/clk.h> 209ac33b0cSPeter Ujfalusi #include <linux/clk-provider.h> 219ac33b0cSPeter Ujfalusi #include <linux/slab.h> 229ac33b0cSPeter Ujfalusi #include <linux/io.h> 239ac33b0cSPeter Ujfalusi #include <linux/of.h> 249ac33b0cSPeter Ujfalusi #include <linux/of_address.h> 259ac33b0cSPeter Ujfalusi #include <linux/platform_device.h> 269ac33b0cSPeter Ujfalusi #include <linux/pm_runtime.h> 279ac33b0cSPeter Ujfalusi 289ac33b0cSPeter Ujfalusi #define DRA7_ATL_INSTANCES 4 299ac33b0cSPeter Ujfalusi 309ac33b0cSPeter Ujfalusi #define DRA7_ATL_PPMR_REG(id) (0x200 + (id * 0x80)) 319ac33b0cSPeter Ujfalusi #define DRA7_ATL_BBSR_REG(id) (0x204 + (id * 0x80)) 329ac33b0cSPeter Ujfalusi #define DRA7_ATL_ATLCR_REG(id) (0x208 + (id * 0x80)) 339ac33b0cSPeter Ujfalusi #define DRA7_ATL_SWEN_REG(id) (0x210 + (id * 0x80)) 349ac33b0cSPeter Ujfalusi #define DRA7_ATL_BWSMUX_REG(id) (0x214 + (id * 0x80)) 359ac33b0cSPeter Ujfalusi #define DRA7_ATL_AWSMUX_REG(id) (0x218 + (id * 0x80)) 369ac33b0cSPeter Ujfalusi #define DRA7_ATL_PCLKMUX_REG(id) (0x21c + (id * 0x80)) 379ac33b0cSPeter Ujfalusi 389ac33b0cSPeter Ujfalusi #define DRA7_ATL_SWEN BIT(0) 399ac33b0cSPeter Ujfalusi #define DRA7_ATL_DIVIDER_MASK (0x1f) 409ac33b0cSPeter Ujfalusi #define DRA7_ATL_PCLKMUX BIT(0) 419ac33b0cSPeter Ujfalusi struct dra7_atl_clock_info; 429ac33b0cSPeter Ujfalusi 439ac33b0cSPeter Ujfalusi struct dra7_atl_desc { 449ac33b0cSPeter Ujfalusi struct clk *clk; 459ac33b0cSPeter Ujfalusi struct clk_hw hw; 469ac33b0cSPeter Ujfalusi struct dra7_atl_clock_info *cinfo; 479ac33b0cSPeter Ujfalusi int id; 489ac33b0cSPeter Ujfalusi 499ac33b0cSPeter Ujfalusi bool probed; /* the driver for the IP has been loaded */ 509ac33b0cSPeter Ujfalusi bool valid; /* configured */ 519ac33b0cSPeter Ujfalusi bool enabled; 529ac33b0cSPeter Ujfalusi u32 bws; /* Baseband Word Select Mux */ 539ac33b0cSPeter Ujfalusi u32 aws; /* Audio Word Select Mux */ 549ac33b0cSPeter Ujfalusi u32 divider; /* Cached divider value */ 559ac33b0cSPeter Ujfalusi }; 569ac33b0cSPeter Ujfalusi 579ac33b0cSPeter Ujfalusi struct dra7_atl_clock_info { 589ac33b0cSPeter Ujfalusi struct device *dev; 599ac33b0cSPeter Ujfalusi void __iomem *iobase; 609ac33b0cSPeter Ujfalusi 619ac33b0cSPeter Ujfalusi struct dra7_atl_desc *cdesc; 629ac33b0cSPeter Ujfalusi }; 639ac33b0cSPeter Ujfalusi 649ac33b0cSPeter Ujfalusi #define to_atl_desc(_hw) container_of(_hw, struct dra7_atl_desc, hw) 659ac33b0cSPeter Ujfalusi 669ac33b0cSPeter Ujfalusi static inline void atl_write(struct dra7_atl_clock_info *cinfo, u32 reg, 679ac33b0cSPeter Ujfalusi u32 val) 689ac33b0cSPeter Ujfalusi { 699ac33b0cSPeter Ujfalusi __raw_writel(val, cinfo->iobase + reg); 709ac33b0cSPeter Ujfalusi } 719ac33b0cSPeter Ujfalusi 729ac33b0cSPeter Ujfalusi static inline int atl_read(struct dra7_atl_clock_info *cinfo, u32 reg) 739ac33b0cSPeter Ujfalusi { 749ac33b0cSPeter Ujfalusi return __raw_readl(cinfo->iobase + reg); 759ac33b0cSPeter Ujfalusi } 769ac33b0cSPeter Ujfalusi 779ac33b0cSPeter Ujfalusi static int atl_clk_enable(struct clk_hw *hw) 789ac33b0cSPeter Ujfalusi { 799ac33b0cSPeter Ujfalusi struct dra7_atl_desc *cdesc = to_atl_desc(hw); 809ac33b0cSPeter Ujfalusi 819ac33b0cSPeter Ujfalusi if (!cdesc->probed) 829ac33b0cSPeter Ujfalusi goto out; 839ac33b0cSPeter Ujfalusi 849ac33b0cSPeter Ujfalusi if (unlikely(!cdesc->valid)) 859ac33b0cSPeter Ujfalusi dev_warn(cdesc->cinfo->dev, "atl%d has not been configured\n", 869ac33b0cSPeter Ujfalusi cdesc->id); 879ac33b0cSPeter Ujfalusi pm_runtime_get_sync(cdesc->cinfo->dev); 889ac33b0cSPeter Ujfalusi 899ac33b0cSPeter Ujfalusi atl_write(cdesc->cinfo, DRA7_ATL_ATLCR_REG(cdesc->id), 909ac33b0cSPeter Ujfalusi cdesc->divider - 1); 919ac33b0cSPeter Ujfalusi atl_write(cdesc->cinfo, DRA7_ATL_SWEN_REG(cdesc->id), DRA7_ATL_SWEN); 929ac33b0cSPeter Ujfalusi 939ac33b0cSPeter Ujfalusi out: 949ac33b0cSPeter Ujfalusi cdesc->enabled = true; 959ac33b0cSPeter Ujfalusi 969ac33b0cSPeter Ujfalusi return 0; 979ac33b0cSPeter Ujfalusi } 989ac33b0cSPeter Ujfalusi 999ac33b0cSPeter Ujfalusi static void atl_clk_disable(struct clk_hw *hw) 1009ac33b0cSPeter Ujfalusi { 1019ac33b0cSPeter Ujfalusi struct dra7_atl_desc *cdesc = to_atl_desc(hw); 1029ac33b0cSPeter Ujfalusi 1039ac33b0cSPeter Ujfalusi if (!cdesc->probed) 1049ac33b0cSPeter Ujfalusi goto out; 1059ac33b0cSPeter Ujfalusi 1069ac33b0cSPeter Ujfalusi atl_write(cdesc->cinfo, DRA7_ATL_SWEN_REG(cdesc->id), 0); 1079ac33b0cSPeter Ujfalusi pm_runtime_put_sync(cdesc->cinfo->dev); 1089ac33b0cSPeter Ujfalusi 1099ac33b0cSPeter Ujfalusi out: 1109ac33b0cSPeter Ujfalusi cdesc->enabled = false; 1119ac33b0cSPeter Ujfalusi } 1129ac33b0cSPeter Ujfalusi 1139ac33b0cSPeter Ujfalusi static int atl_clk_is_enabled(struct clk_hw *hw) 1149ac33b0cSPeter Ujfalusi { 1159ac33b0cSPeter Ujfalusi struct dra7_atl_desc *cdesc = to_atl_desc(hw); 1169ac33b0cSPeter Ujfalusi 1179ac33b0cSPeter Ujfalusi return cdesc->enabled; 1189ac33b0cSPeter Ujfalusi } 1199ac33b0cSPeter Ujfalusi 1209ac33b0cSPeter Ujfalusi static unsigned long atl_clk_recalc_rate(struct clk_hw *hw, 1219ac33b0cSPeter Ujfalusi unsigned long parent_rate) 1229ac33b0cSPeter Ujfalusi { 1239ac33b0cSPeter Ujfalusi struct dra7_atl_desc *cdesc = to_atl_desc(hw); 1249ac33b0cSPeter Ujfalusi 1259ac33b0cSPeter Ujfalusi return parent_rate / cdesc->divider; 1269ac33b0cSPeter Ujfalusi } 1279ac33b0cSPeter Ujfalusi 1289ac33b0cSPeter Ujfalusi static long atl_clk_round_rate(struct clk_hw *hw, unsigned long rate, 1299ac33b0cSPeter Ujfalusi unsigned long *parent_rate) 1309ac33b0cSPeter Ujfalusi { 1319ac33b0cSPeter Ujfalusi unsigned divider; 1329ac33b0cSPeter Ujfalusi 1339ac33b0cSPeter Ujfalusi divider = (*parent_rate + rate / 2) / rate; 1349ac33b0cSPeter Ujfalusi if (divider > DRA7_ATL_DIVIDER_MASK + 1) 1359ac33b0cSPeter Ujfalusi divider = DRA7_ATL_DIVIDER_MASK + 1; 1369ac33b0cSPeter Ujfalusi 1379ac33b0cSPeter Ujfalusi return *parent_rate / divider; 1389ac33b0cSPeter Ujfalusi } 1399ac33b0cSPeter Ujfalusi 1409ac33b0cSPeter Ujfalusi static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate, 1419ac33b0cSPeter Ujfalusi unsigned long parent_rate) 1429ac33b0cSPeter Ujfalusi { 14320411dadSNishanth Menon struct dra7_atl_desc *cdesc; 1449ac33b0cSPeter Ujfalusi u32 divider; 1459ac33b0cSPeter Ujfalusi 14620411dadSNishanth Menon if (!hw || !rate) 14720411dadSNishanth Menon return -EINVAL; 14820411dadSNishanth Menon 14920411dadSNishanth Menon cdesc = to_atl_desc(hw); 1509ac33b0cSPeter Ujfalusi divider = ((parent_rate + rate / 2) / rate) - 1; 1519ac33b0cSPeter Ujfalusi if (divider > DRA7_ATL_DIVIDER_MASK) 1529ac33b0cSPeter Ujfalusi divider = DRA7_ATL_DIVIDER_MASK; 1539ac33b0cSPeter Ujfalusi 1549ac33b0cSPeter Ujfalusi cdesc->divider = divider + 1; 1559ac33b0cSPeter Ujfalusi 1569ac33b0cSPeter Ujfalusi return 0; 1579ac33b0cSPeter Ujfalusi } 1589ac33b0cSPeter Ujfalusi 159412d6b47SStephen Boyd static const struct clk_ops atl_clk_ops = { 1609ac33b0cSPeter Ujfalusi .enable = atl_clk_enable, 1619ac33b0cSPeter Ujfalusi .disable = atl_clk_disable, 1629ac33b0cSPeter Ujfalusi .is_enabled = atl_clk_is_enabled, 1639ac33b0cSPeter Ujfalusi .recalc_rate = atl_clk_recalc_rate, 1649ac33b0cSPeter Ujfalusi .round_rate = atl_clk_round_rate, 1659ac33b0cSPeter Ujfalusi .set_rate = atl_clk_set_rate, 1669ac33b0cSPeter Ujfalusi }; 1679ac33b0cSPeter Ujfalusi 1689ac33b0cSPeter Ujfalusi static void __init of_dra7_atl_clock_setup(struct device_node *node) 1699ac33b0cSPeter Ujfalusi { 1709ac33b0cSPeter Ujfalusi struct dra7_atl_desc *clk_hw = NULL; 171412d6b47SStephen Boyd struct clk_init_data init = { NULL }; 1729ac33b0cSPeter Ujfalusi const char **parent_names = NULL; 1739ac33b0cSPeter Ujfalusi struct clk *clk; 1749ac33b0cSPeter Ujfalusi 1759ac33b0cSPeter Ujfalusi clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); 1769ac33b0cSPeter Ujfalusi if (!clk_hw) { 1779ac33b0cSPeter Ujfalusi pr_err("%s: could not allocate dra7_atl_desc\n", __func__); 1789ac33b0cSPeter Ujfalusi return; 1799ac33b0cSPeter Ujfalusi } 1809ac33b0cSPeter Ujfalusi 1819ac33b0cSPeter Ujfalusi clk_hw->hw.init = &init; 1829ac33b0cSPeter Ujfalusi clk_hw->divider = 1; 1839ac33b0cSPeter Ujfalusi init.name = node->name; 1849ac33b0cSPeter Ujfalusi init.ops = &atl_clk_ops; 1859ac33b0cSPeter Ujfalusi init.flags = CLK_IGNORE_UNUSED; 1869ac33b0cSPeter Ujfalusi init.num_parents = of_clk_get_parent_count(node); 1879ac33b0cSPeter Ujfalusi 1889ac33b0cSPeter Ujfalusi if (init.num_parents != 1) { 1899ac33b0cSPeter Ujfalusi pr_err("%s: atl clock %s must have 1 parent\n", __func__, 1909ac33b0cSPeter Ujfalusi node->name); 1919ac33b0cSPeter Ujfalusi goto cleanup; 1929ac33b0cSPeter Ujfalusi } 1939ac33b0cSPeter Ujfalusi 1949ac33b0cSPeter Ujfalusi parent_names = kzalloc(sizeof(char *), GFP_KERNEL); 1959ac33b0cSPeter Ujfalusi 1969ac33b0cSPeter Ujfalusi if (!parent_names) 1979ac33b0cSPeter Ujfalusi goto cleanup; 1989ac33b0cSPeter Ujfalusi 1999ac33b0cSPeter Ujfalusi parent_names[0] = of_clk_get_parent_name(node, 0); 2009ac33b0cSPeter Ujfalusi 2019ac33b0cSPeter Ujfalusi init.parent_names = parent_names; 2029ac33b0cSPeter Ujfalusi 2039ac33b0cSPeter Ujfalusi clk = clk_register(NULL, &clk_hw->hw); 2049ac33b0cSPeter Ujfalusi 2059ac33b0cSPeter Ujfalusi if (!IS_ERR(clk)) { 2069ac33b0cSPeter Ujfalusi of_clk_add_provider(node, of_clk_src_simple_get, clk); 20773b5d5f7STero Kristo kfree(parent_names); 2089ac33b0cSPeter Ujfalusi return; 2099ac33b0cSPeter Ujfalusi } 2109ac33b0cSPeter Ujfalusi cleanup: 2119ac33b0cSPeter Ujfalusi kfree(parent_names); 2129ac33b0cSPeter Ujfalusi kfree(clk_hw); 2139ac33b0cSPeter Ujfalusi } 2149ac33b0cSPeter Ujfalusi CLK_OF_DECLARE(dra7_atl_clock, "ti,dra7-atl-clock", of_dra7_atl_clock_setup); 2159ac33b0cSPeter Ujfalusi 2169ac33b0cSPeter Ujfalusi static int of_dra7_atl_clk_probe(struct platform_device *pdev) 2179ac33b0cSPeter Ujfalusi { 2189ac33b0cSPeter Ujfalusi struct device_node *node = pdev->dev.of_node; 2199ac33b0cSPeter Ujfalusi struct dra7_atl_clock_info *cinfo; 2209ac33b0cSPeter Ujfalusi int i; 2219ac33b0cSPeter Ujfalusi int ret = 0; 2229ac33b0cSPeter Ujfalusi 2239ac33b0cSPeter Ujfalusi if (!node) 2249ac33b0cSPeter Ujfalusi return -ENODEV; 2259ac33b0cSPeter Ujfalusi 2269ac33b0cSPeter Ujfalusi cinfo = devm_kzalloc(&pdev->dev, sizeof(*cinfo), GFP_KERNEL); 2279ac33b0cSPeter Ujfalusi if (!cinfo) 2289ac33b0cSPeter Ujfalusi return -ENOMEM; 2299ac33b0cSPeter Ujfalusi 2309ac33b0cSPeter Ujfalusi cinfo->iobase = of_iomap(node, 0); 2319ac33b0cSPeter Ujfalusi cinfo->dev = &pdev->dev; 2329ac33b0cSPeter Ujfalusi pm_runtime_enable(cinfo->dev); 23304ed831fSPeter Ujfalusi pm_runtime_irq_safe(cinfo->dev); 2349ac33b0cSPeter Ujfalusi 2359ac33b0cSPeter Ujfalusi pm_runtime_get_sync(cinfo->dev); 2369ac33b0cSPeter Ujfalusi atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); 2379ac33b0cSPeter Ujfalusi 2389ac33b0cSPeter Ujfalusi for (i = 0; i < DRA7_ATL_INSTANCES; i++) { 2399ac33b0cSPeter Ujfalusi struct device_node *cfg_node; 2409ac33b0cSPeter Ujfalusi char prop[5]; 2419ac33b0cSPeter Ujfalusi struct dra7_atl_desc *cdesc; 2429ac33b0cSPeter Ujfalusi struct of_phandle_args clkspec; 2439ac33b0cSPeter Ujfalusi struct clk *clk; 2449ac33b0cSPeter Ujfalusi int rc; 2459ac33b0cSPeter Ujfalusi 2469ac33b0cSPeter Ujfalusi rc = of_parse_phandle_with_args(node, "ti,provided-clocks", 2479ac33b0cSPeter Ujfalusi NULL, i, &clkspec); 2489ac33b0cSPeter Ujfalusi 2499ac33b0cSPeter Ujfalusi if (rc) { 2509ac33b0cSPeter Ujfalusi pr_err("%s: failed to lookup atl clock %d\n", __func__, 2519ac33b0cSPeter Ujfalusi i); 2529ac33b0cSPeter Ujfalusi return -EINVAL; 2539ac33b0cSPeter Ujfalusi } 2549ac33b0cSPeter Ujfalusi 2559ac33b0cSPeter Ujfalusi clk = of_clk_get_from_provider(&clkspec); 256e0cdcda5SKrzysztof Kozlowski if (IS_ERR(clk)) { 257e0cdcda5SKrzysztof Kozlowski pr_err("%s: failed to get atl clock %d from provider\n", 258e0cdcda5SKrzysztof Kozlowski __func__, i); 259e0cdcda5SKrzysztof Kozlowski return PTR_ERR(clk); 260e0cdcda5SKrzysztof Kozlowski } 2619ac33b0cSPeter Ujfalusi 2629ac33b0cSPeter Ujfalusi cdesc = to_atl_desc(__clk_get_hw(clk)); 2639ac33b0cSPeter Ujfalusi cdesc->cinfo = cinfo; 2649ac33b0cSPeter Ujfalusi cdesc->id = i; 2659ac33b0cSPeter Ujfalusi 2669ac33b0cSPeter Ujfalusi /* Get configuration for the ATL instances */ 2679ac33b0cSPeter Ujfalusi snprintf(prop, sizeof(prop), "atl%u", i); 268660e1551SPeter Ujfalusi of_node_get(node); 2699ac33b0cSPeter Ujfalusi cfg_node = of_find_node_by_name(node, prop); 2709ac33b0cSPeter Ujfalusi if (cfg_node) { 2719ac33b0cSPeter Ujfalusi ret = of_property_read_u32(cfg_node, "bws", 2729ac33b0cSPeter Ujfalusi &cdesc->bws); 2739ac33b0cSPeter Ujfalusi ret |= of_property_read_u32(cfg_node, "aws", 2749ac33b0cSPeter Ujfalusi &cdesc->aws); 2759ac33b0cSPeter Ujfalusi if (!ret) { 2769ac33b0cSPeter Ujfalusi cdesc->valid = true; 2779ac33b0cSPeter Ujfalusi atl_write(cinfo, DRA7_ATL_BWSMUX_REG(i), 2789ac33b0cSPeter Ujfalusi cdesc->bws); 2799ac33b0cSPeter Ujfalusi atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i), 2809ac33b0cSPeter Ujfalusi cdesc->aws); 2819ac33b0cSPeter Ujfalusi } 282660e1551SPeter Ujfalusi of_node_put(cfg_node); 2839ac33b0cSPeter Ujfalusi } 2849ac33b0cSPeter Ujfalusi 2859ac33b0cSPeter Ujfalusi cdesc->probed = true; 2869ac33b0cSPeter Ujfalusi /* 2879ac33b0cSPeter Ujfalusi * Enable the clock if it has been asked prior to loading the 2889ac33b0cSPeter Ujfalusi * hw driver 2899ac33b0cSPeter Ujfalusi */ 2909ac33b0cSPeter Ujfalusi if (cdesc->enabled) 2919ac33b0cSPeter Ujfalusi atl_clk_enable(__clk_get_hw(clk)); 2929ac33b0cSPeter Ujfalusi } 2939ac33b0cSPeter Ujfalusi pm_runtime_put_sync(cinfo->dev); 2949ac33b0cSPeter Ujfalusi 2959ac33b0cSPeter Ujfalusi return ret; 2969ac33b0cSPeter Ujfalusi } 2979ac33b0cSPeter Ujfalusi 2989ac33b0cSPeter Ujfalusi static int of_dra7_atl_clk_remove(struct platform_device *pdev) 2999ac33b0cSPeter Ujfalusi { 3009ac33b0cSPeter Ujfalusi pm_runtime_disable(&pdev->dev); 3019ac33b0cSPeter Ujfalusi 3029ac33b0cSPeter Ujfalusi return 0; 3039ac33b0cSPeter Ujfalusi } 3049ac33b0cSPeter Ujfalusi 305f375573cSFabian Frederick static const struct of_device_id of_dra7_atl_clk_match_tbl[] = { 3069ac33b0cSPeter Ujfalusi { .compatible = "ti,dra7-atl", }, 3079ac33b0cSPeter Ujfalusi {}, 3089ac33b0cSPeter Ujfalusi }; 3099ac33b0cSPeter Ujfalusi MODULE_DEVICE_TABLE(of, of_dra7_atl_clk_match_tbl); 3109ac33b0cSPeter Ujfalusi 3119ac33b0cSPeter Ujfalusi static struct platform_driver dra7_atl_clk_driver = { 3129ac33b0cSPeter Ujfalusi .driver = { 3139ac33b0cSPeter Ujfalusi .name = "dra7-atl", 3149ac33b0cSPeter Ujfalusi .of_match_table = of_dra7_atl_clk_match_tbl, 3159ac33b0cSPeter Ujfalusi }, 3169ac33b0cSPeter Ujfalusi .probe = of_dra7_atl_clk_probe, 3179ac33b0cSPeter Ujfalusi .remove = of_dra7_atl_clk_remove, 3189ac33b0cSPeter Ujfalusi }; 3199ac33b0cSPeter Ujfalusi 3209ac33b0cSPeter Ujfalusi module_platform_driver(dra7_atl_clk_driver); 3219ac33b0cSPeter Ujfalusi 3229ac33b0cSPeter Ujfalusi MODULE_DESCRIPTION("Clock driver for DRA7 Audio Tracking Logic"); 3239ac33b0cSPeter Ujfalusi MODULE_ALIAS("platform:dra7-atl-clock"); 3249ac33b0cSPeter Ujfalusi MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); 3259ac33b0cSPeter Ujfalusi MODULE_LICENSE("GPL v2"); 326