cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sci-clk.c (18349B)


      1/*
      2 * SCI Clock driver for keystone based devices
      3 *
      4 * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
      5 *	Tero Kristo <t-kristo@ti.com>
      6 *
      7 * This program is free software; you can redistribute it and/or modify
      8 * it under the terms of the GNU General Public License version 2 as
      9 * published by the Free Software Foundation.
     10 *
     11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     12 * kind, whether express or implied; without even the implied warranty
     13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 */
     16#include <linux/clk-provider.h>
     17#include <linux/err.h>
     18#include <linux/io.h>
     19#include <linux/module.h>
     20#include <linux/of_address.h>
     21#include <linux/of_device.h>
     22#include <linux/platform_device.h>
     23#include <linux/slab.h>
     24#include <linux/soc/ti/ti_sci_protocol.h>
     25#include <linux/bsearch.h>
     26#include <linux/list_sort.h>
     27
     28#define SCI_CLK_SSC_ENABLE		BIT(0)
     29#define SCI_CLK_ALLOW_FREQ_CHANGE	BIT(1)
     30#define SCI_CLK_INPUT_TERMINATION	BIT(2)
     31
     32/**
     33 * struct sci_clk_provider - TI SCI clock provider representation
     34 * @sci: Handle to the System Control Interface protocol handler
     35 * @ops: Pointer to the SCI ops to be used by the clocks
     36 * @dev: Device pointer for the clock provider
     37 * @clocks: Clocks array for this device
     38 * @num_clocks: Total number of clocks for this provider
     39 */
     40struct sci_clk_provider {
     41	const struct ti_sci_handle *sci;
     42	const struct ti_sci_clk_ops *ops;
     43	struct device *dev;
     44	struct sci_clk **clocks;
     45	int num_clocks;
     46};
     47
     48/**
     49 * struct sci_clk - TI SCI clock representation
     50 * @hw:		 Hardware clock cookie for common clock framework
     51 * @dev_id:	 Device index
     52 * @clk_id:	 Clock index
     53 * @num_parents: Number of parents for this clock
     54 * @provider:	 Master clock provider
     55 * @flags:	 Flags for the clock
     56 * @node:	 Link for handling clocks probed via DT
     57 * @cached_req:	 Cached requested freq for determine rate calls
     58 * @cached_res:	 Cached result freq for determine rate calls
     59 */
     60struct sci_clk {
     61	struct clk_hw hw;
     62	u16 dev_id;
     63	u32 clk_id;
     64	u32 num_parents;
     65	struct sci_clk_provider *provider;
     66	u8 flags;
     67	struct list_head node;
     68	unsigned long cached_req;
     69	unsigned long cached_res;
     70};
     71
     72#define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
     73
     74/**
     75 * sci_clk_prepare - Prepare (enable) a TI SCI clock
     76 * @hw: clock to prepare
     77 *
     78 * Prepares a clock to be actively used. Returns the SCI protocol status.
     79 */
     80static int sci_clk_prepare(struct clk_hw *hw)
     81{
     82	struct sci_clk *clk = to_sci_clk(hw);
     83	bool enable_ssc = clk->flags & SCI_CLK_SSC_ENABLE;
     84	bool allow_freq_change = clk->flags & SCI_CLK_ALLOW_FREQ_CHANGE;
     85	bool input_termination = clk->flags & SCI_CLK_INPUT_TERMINATION;
     86
     87	return clk->provider->ops->get_clock(clk->provider->sci, clk->dev_id,
     88					     clk->clk_id, enable_ssc,
     89					     allow_freq_change,
     90					     input_termination);
     91}
     92
     93/**
     94 * sci_clk_unprepare - Un-prepares (disables) a TI SCI clock
     95 * @hw: clock to unprepare
     96 *
     97 * Un-prepares a clock from active state.
     98 */
     99static void sci_clk_unprepare(struct clk_hw *hw)
    100{
    101	struct sci_clk *clk = to_sci_clk(hw);
    102	int ret;
    103
    104	ret = clk->provider->ops->put_clock(clk->provider->sci, clk->dev_id,
    105					    clk->clk_id);
    106	if (ret)
    107		dev_err(clk->provider->dev,
    108			"unprepare failed for dev=%d, clk=%d, ret=%d\n",
    109			clk->dev_id, clk->clk_id, ret);
    110}
    111
    112/**
    113 * sci_clk_is_prepared - Check if a TI SCI clock is prepared or not
    114 * @hw: clock to check status for
    115 *
    116 * Checks if a clock is prepared (enabled) in hardware. Returns non-zero
    117 * value if clock is enabled, zero otherwise.
    118 */
    119static int sci_clk_is_prepared(struct clk_hw *hw)
    120{
    121	struct sci_clk *clk = to_sci_clk(hw);
    122	bool req_state, current_state;
    123	int ret;
    124
    125	ret = clk->provider->ops->is_on(clk->provider->sci, clk->dev_id,
    126					clk->clk_id, &req_state,
    127					&current_state);
    128	if (ret) {
    129		dev_err(clk->provider->dev,
    130			"is_prepared failed for dev=%d, clk=%d, ret=%d\n",
    131			clk->dev_id, clk->clk_id, ret);
    132		return 0;
    133	}
    134
    135	return req_state;
    136}
    137
    138/**
    139 * sci_clk_recalc_rate - Get clock rate for a TI SCI clock
    140 * @hw: clock to get rate for
    141 * @parent_rate: parent rate provided by common clock framework, not used
    142 *
    143 * Gets the current clock rate of a TI SCI clock. Returns the current
    144 * clock rate, or zero in failure.
    145 */
    146static unsigned long sci_clk_recalc_rate(struct clk_hw *hw,
    147					 unsigned long parent_rate)
    148{
    149	struct sci_clk *clk = to_sci_clk(hw);
    150	u64 freq;
    151	int ret;
    152
    153	ret = clk->provider->ops->get_freq(clk->provider->sci, clk->dev_id,
    154					   clk->clk_id, &freq);
    155	if (ret) {
    156		dev_err(clk->provider->dev,
    157			"recalc-rate failed for dev=%d, clk=%d, ret=%d\n",
    158			clk->dev_id, clk->clk_id, ret);
    159		return 0;
    160	}
    161
    162	return freq;
    163}
    164
    165/**
    166 * sci_clk_determine_rate - Determines a clock rate a clock can be set to
    167 * @hw: clock to change rate for
    168 * @req: requested rate configuration for the clock
    169 *
    170 * Determines a suitable clock rate and parent for a TI SCI clock.
    171 * The parent handling is un-used, as generally the parent clock rates
    172 * are not known by the kernel; instead these are internally handled
    173 * by the firmware. Returns 0 on success, negative error value on failure.
    174 */
    175static int sci_clk_determine_rate(struct clk_hw *hw,
    176				  struct clk_rate_request *req)
    177{
    178	struct sci_clk *clk = to_sci_clk(hw);
    179	int ret;
    180	u64 new_rate;
    181
    182	if (clk->cached_req && clk->cached_req == req->rate) {
    183		req->rate = clk->cached_res;
    184		return 0;
    185	}
    186
    187	ret = clk->provider->ops->get_best_match_freq(clk->provider->sci,
    188						      clk->dev_id,
    189						      clk->clk_id,
    190						      req->min_rate,
    191						      req->rate,
    192						      req->max_rate,
    193						      &new_rate);
    194	if (ret) {
    195		dev_err(clk->provider->dev,
    196			"determine-rate failed for dev=%d, clk=%d, ret=%d\n",
    197			clk->dev_id, clk->clk_id, ret);
    198		return ret;
    199	}
    200
    201	clk->cached_req = req->rate;
    202	clk->cached_res = new_rate;
    203
    204	req->rate = new_rate;
    205
    206	return 0;
    207}
    208
    209/**
    210 * sci_clk_set_rate - Set rate for a TI SCI clock
    211 * @hw: clock to change rate for
    212 * @rate: target rate for the clock
    213 * @parent_rate: rate of the clock parent, not used for TI SCI clocks
    214 *
    215 * Sets a clock frequency for a TI SCI clock. Returns the TI SCI
    216 * protocol status.
    217 */
    218static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
    219			    unsigned long parent_rate)
    220{
    221	struct sci_clk *clk = to_sci_clk(hw);
    222
    223	return clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
    224					    clk->clk_id, rate / 10 * 9, rate,
    225					    rate / 10 * 11);
    226}
    227
    228/**
    229 * sci_clk_get_parent - Get the current parent of a TI SCI clock
    230 * @hw: clock to get parent for
    231 *
    232 * Returns the index of the currently selected parent for a TI SCI clock.
    233 */
    234static u8 sci_clk_get_parent(struct clk_hw *hw)
    235{
    236	struct sci_clk *clk = to_sci_clk(hw);
    237	u32 parent_id = 0;
    238	int ret;
    239
    240	ret = clk->provider->ops->get_parent(clk->provider->sci, clk->dev_id,
    241					     clk->clk_id, (void *)&parent_id);
    242	if (ret) {
    243		dev_err(clk->provider->dev,
    244			"get-parent failed for dev=%d, clk=%d, ret=%d\n",
    245			clk->dev_id, clk->clk_id, ret);
    246		return 0;
    247	}
    248
    249	parent_id = parent_id - clk->clk_id - 1;
    250
    251	return (u8)parent_id;
    252}
    253
    254/**
    255 * sci_clk_set_parent - Set the parent of a TI SCI clock
    256 * @hw: clock to set parent for
    257 * @index: new parent index for the clock
    258 *
    259 * Sets the parent of a TI SCI clock. Return TI SCI protocol status.
    260 */
    261static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
    262{
    263	struct sci_clk *clk = to_sci_clk(hw);
    264
    265	clk->cached_req = 0;
    266
    267	return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
    268					      clk->clk_id,
    269					      index + 1 + clk->clk_id);
    270}
    271
    272static const struct clk_ops sci_clk_ops = {
    273	.prepare = sci_clk_prepare,
    274	.unprepare = sci_clk_unprepare,
    275	.is_prepared = sci_clk_is_prepared,
    276	.recalc_rate = sci_clk_recalc_rate,
    277	.determine_rate = sci_clk_determine_rate,
    278	.set_rate = sci_clk_set_rate,
    279	.get_parent = sci_clk_get_parent,
    280	.set_parent = sci_clk_set_parent,
    281};
    282
    283/**
    284 * _sci_clk_get - Gets a handle for an SCI clock
    285 * @provider: Handle to SCI clock provider
    286 * @sci_clk: Handle to the SCI clock to populate
    287 *
    288 * Gets a handle to an existing TI SCI hw clock, or builds a new clock
    289 * entry and registers it with the common clock framework. Called from
    290 * the common clock framework, when a corresponding of_clk_get call is
    291 * executed, or recursively from itself when parsing parent clocks.
    292 * Returns 0 on success, negative error code on failure.
    293 */
    294static int _sci_clk_build(struct sci_clk_provider *provider,
    295			  struct sci_clk *sci_clk)
    296{
    297	struct clk_init_data init = { NULL };
    298	char *name = NULL;
    299	char **parent_names = NULL;
    300	int i;
    301	int ret = 0;
    302
    303	name = kasprintf(GFP_KERNEL, "clk:%d:%d", sci_clk->dev_id,
    304			 sci_clk->clk_id);
    305
    306	init.name = name;
    307
    308	/*
    309	 * From kernel point of view, we only care about a clocks parents,
    310	 * if it has more than 1 possible parent. In this case, it is going
    311	 * to have mux functionality. Otherwise it is going to act as a root
    312	 * clock.
    313	 */
    314	if (sci_clk->num_parents < 2)
    315		sci_clk->num_parents = 0;
    316
    317	if (sci_clk->num_parents) {
    318		parent_names = kcalloc(sci_clk->num_parents, sizeof(char *),
    319				       GFP_KERNEL);
    320
    321		if (!parent_names) {
    322			ret = -ENOMEM;
    323			goto err;
    324		}
    325
    326		for (i = 0; i < sci_clk->num_parents; i++) {
    327			char *parent_name;
    328
    329			parent_name = kasprintf(GFP_KERNEL, "clk:%d:%d",
    330						sci_clk->dev_id,
    331						sci_clk->clk_id + 1 + i);
    332			if (!parent_name) {
    333				ret = -ENOMEM;
    334				goto err;
    335			}
    336			parent_names[i] = parent_name;
    337		}
    338		init.parent_names = (void *)parent_names;
    339	}
    340
    341	init.ops = &sci_clk_ops;
    342	init.num_parents = sci_clk->num_parents;
    343	sci_clk->hw.init = &init;
    344
    345	ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
    346	if (ret)
    347		dev_err(provider->dev, "failed clk register with %d\n", ret);
    348
    349err:
    350	if (parent_names) {
    351		for (i = 0; i < sci_clk->num_parents; i++)
    352			kfree(parent_names[i]);
    353
    354		kfree(parent_names);
    355	}
    356
    357	kfree(name);
    358
    359	return ret;
    360}
    361
    362static int _cmp_sci_clk(const void *a, const void *b)
    363{
    364	const struct sci_clk *ca = a;
    365	const struct sci_clk *cb = *(struct sci_clk **)b;
    366
    367	if (ca->dev_id == cb->dev_id && ca->clk_id == cb->clk_id)
    368		return 0;
    369	if (ca->dev_id > cb->dev_id ||
    370	    (ca->dev_id == cb->dev_id && ca->clk_id > cb->clk_id))
    371		return 1;
    372	return -1;
    373}
    374
    375/**
    376 * sci_clk_get - Xlate function for getting clock handles
    377 * @clkspec: device tree clock specifier
    378 * @data: pointer to the clock provider
    379 *
    380 * Xlate function for retrieving clock TI SCI hw clock handles based on
    381 * device tree clock specifier. Called from the common clock framework,
    382 * when a corresponding of_clk_get call is executed. Returns a pointer
    383 * to the TI SCI hw clock struct, or ERR_PTR value in failure.
    384 */
    385static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data)
    386{
    387	struct sci_clk_provider *provider = data;
    388	struct sci_clk **clk;
    389	struct sci_clk key;
    390
    391	if (clkspec->args_count != 2)
    392		return ERR_PTR(-EINVAL);
    393
    394	key.dev_id = clkspec->args[0];
    395	key.clk_id = clkspec->args[1];
    396
    397	clk = bsearch(&key, provider->clocks, provider->num_clocks,
    398		      sizeof(clk), _cmp_sci_clk);
    399
    400	if (!clk)
    401		return ERR_PTR(-ENODEV);
    402
    403	return &(*clk)->hw;
    404}
    405
    406static int ti_sci_init_clocks(struct sci_clk_provider *p)
    407{
    408	int i;
    409	int ret;
    410
    411	for (i = 0; i < p->num_clocks; i++) {
    412		ret = _sci_clk_build(p, p->clocks[i]);
    413		if (ret)
    414			return ret;
    415	}
    416
    417	return 0;
    418}
    419
    420static const struct of_device_id ti_sci_clk_of_match[] = {
    421	{ .compatible = "ti,k2g-sci-clk" },
    422	{ /* Sentinel */ },
    423};
    424MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match);
    425
    426#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
    427static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
    428{
    429	int ret;
    430	int num_clks = 0;
    431	struct sci_clk **clks = NULL;
    432	struct sci_clk **tmp_clks;
    433	struct sci_clk *sci_clk;
    434	int max_clks = 0;
    435	int clk_id = 0;
    436	int dev_id = 0;
    437	u32 num_parents = 0;
    438	int gap_size = 0;
    439	struct device *dev = provider->dev;
    440
    441	while (1) {
    442		ret = provider->ops->get_num_parents(provider->sci, dev_id,
    443						     clk_id,
    444						     (void *)&num_parents);
    445		if (ret) {
    446			gap_size++;
    447			if (!clk_id) {
    448				if (gap_size >= 5)
    449					break;
    450				dev_id++;
    451			} else {
    452				if (gap_size >= 2) {
    453					dev_id++;
    454					clk_id = 0;
    455					gap_size = 0;
    456				} else {
    457					clk_id++;
    458				}
    459			}
    460			continue;
    461		}
    462
    463		gap_size = 0;
    464
    465		if (num_clks == max_clks) {
    466			tmp_clks = devm_kmalloc_array(dev, max_clks + 64,
    467						      sizeof(sci_clk),
    468						      GFP_KERNEL);
    469			memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk));
    470			if (max_clks)
    471				devm_kfree(dev, clks);
    472			max_clks += 64;
    473			clks = tmp_clks;
    474		}
    475
    476		sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL);
    477		if (!sci_clk)
    478			return -ENOMEM;
    479		sci_clk->dev_id = dev_id;
    480		sci_clk->clk_id = clk_id;
    481		sci_clk->provider = provider;
    482		sci_clk->num_parents = num_parents;
    483
    484		clks[num_clks] = sci_clk;
    485
    486		clk_id++;
    487		num_clks++;
    488	}
    489
    490	provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
    491					      GFP_KERNEL);
    492	if (!provider->clocks)
    493		return -ENOMEM;
    494
    495	memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk));
    496
    497	provider->num_clocks = num_clks;
    498
    499	devm_kfree(dev, clks);
    500
    501	return 0;
    502}
    503
    504#else
    505
    506static int _cmp_sci_clk_list(void *priv, const struct list_head *a,
    507			     const struct list_head *b)
    508{
    509	struct sci_clk *ca = container_of(a, struct sci_clk, node);
    510	struct sci_clk *cb = container_of(b, struct sci_clk, node);
    511
    512	return _cmp_sci_clk(ca, &cb);
    513}
    514
    515static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider)
    516{
    517	struct device *dev = provider->dev;
    518	struct device_node *np = NULL;
    519	int ret;
    520	int index;
    521	struct of_phandle_args args;
    522	struct list_head clks;
    523	struct sci_clk *sci_clk, *prev;
    524	int num_clks = 0;
    525	int num_parents;
    526	int clk_id;
    527	const char * const clk_names[] = {
    528		"clocks", "assigned-clocks", "assigned-clock-parents", NULL
    529	};
    530	const char * const *clk_name;
    531
    532	INIT_LIST_HEAD(&clks);
    533
    534	clk_name = clk_names;
    535
    536	while (*clk_name) {
    537		np = of_find_node_with_property(np, *clk_name);
    538		if (!np) {
    539			clk_name++;
    540			continue;
    541		}
    542
    543		if (!of_device_is_available(np))
    544			continue;
    545
    546		index = 0;
    547
    548		do {
    549			ret = of_parse_phandle_with_args(np, *clk_name,
    550							 "#clock-cells", index,
    551							 &args);
    552			if (ret)
    553				break;
    554
    555			if (args.args_count == 2 && args.np == dev->of_node) {
    556				sci_clk = devm_kzalloc(dev, sizeof(*sci_clk),
    557						       GFP_KERNEL);
    558				if (!sci_clk)
    559					return -ENOMEM;
    560
    561				sci_clk->dev_id = args.args[0];
    562				sci_clk->clk_id = args.args[1];
    563				sci_clk->provider = provider;
    564				provider->ops->get_num_parents(provider->sci,
    565							       sci_clk->dev_id,
    566							       sci_clk->clk_id,
    567							       (void *)&sci_clk->num_parents);
    568				list_add_tail(&sci_clk->node, &clks);
    569
    570				num_clks++;
    571
    572				num_parents = sci_clk->num_parents;
    573				if (num_parents == 1)
    574					num_parents = 0;
    575
    576				/*
    577				 * Linux kernel has inherent limitation
    578				 * of 255 clock parents at the moment.
    579				 * Right now, it is not expected that
    580				 * any mux clock from sci-clk driver
    581				 * would exceed that limit either, but
    582				 * the ABI basically provides that
    583				 * possibility. Print out a warning if
    584				 * this happens for any clock.
    585				 */
    586				if (num_parents >= 255) {
    587					dev_warn(dev, "too many parents for dev=%d, clk=%d (%d), cropping to 255.\n",
    588						 sci_clk->dev_id,
    589						 sci_clk->clk_id, num_parents);
    590					num_parents = 255;
    591				}
    592
    593				clk_id = args.args[1] + 1;
    594
    595				while (num_parents--) {
    596					sci_clk = devm_kzalloc(dev,
    597							       sizeof(*sci_clk),
    598							       GFP_KERNEL);
    599					if (!sci_clk)
    600						return -ENOMEM;
    601					sci_clk->dev_id = args.args[0];
    602					sci_clk->clk_id = clk_id++;
    603					sci_clk->provider = provider;
    604					list_add_tail(&sci_clk->node, &clks);
    605
    606					num_clks++;
    607				}
    608			}
    609
    610			index++;
    611		} while (args.np);
    612	}
    613
    614	list_sort(NULL, &clks, _cmp_sci_clk_list);
    615
    616	provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
    617					      GFP_KERNEL);
    618	if (!provider->clocks)
    619		return -ENOMEM;
    620
    621	num_clks = 0;
    622	prev = NULL;
    623
    624	list_for_each_entry(sci_clk, &clks, node) {
    625		if (prev && prev->dev_id == sci_clk->dev_id &&
    626		    prev->clk_id == sci_clk->clk_id)
    627			continue;
    628
    629		provider->clocks[num_clks++] = sci_clk;
    630		prev = sci_clk;
    631	}
    632
    633	provider->num_clocks = num_clks;
    634
    635	return 0;
    636}
    637#endif
    638
    639/**
    640 * ti_sci_clk_probe - Probe function for the TI SCI clock driver
    641 * @pdev: platform device pointer to be probed
    642 *
    643 * Probes the TI SCI clock device. Allocates a new clock provider
    644 * and registers this to the common clock framework. Also applies
    645 * any required flags to the identified clocks via clock lists
    646 * supplied from DT. Returns 0 for success, negative error value
    647 * for failure.
    648 */
    649static int ti_sci_clk_probe(struct platform_device *pdev)
    650{
    651	struct device *dev = &pdev->dev;
    652	struct device_node *np = dev->of_node;
    653	struct sci_clk_provider *provider;
    654	const struct ti_sci_handle *handle;
    655	int ret;
    656
    657	handle = devm_ti_sci_get_handle(dev);
    658	if (IS_ERR(handle))
    659		return PTR_ERR(handle);
    660
    661	provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
    662	if (!provider)
    663		return -ENOMEM;
    664
    665	provider->sci = handle;
    666	provider->ops = &handle->ops.clk_ops;
    667	provider->dev = dev;
    668
    669#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
    670	ret = ti_sci_scan_clocks_from_fw(provider);
    671	if (ret) {
    672		dev_err(dev, "scan clocks from FW failed: %d\n", ret);
    673		return ret;
    674	}
    675#else
    676	ret = ti_sci_scan_clocks_from_dt(provider);
    677	if (ret) {
    678		dev_err(dev, "scan clocks from DT failed: %d\n", ret);
    679		return ret;
    680	}
    681#endif
    682
    683	ret = ti_sci_init_clocks(provider);
    684	if (ret) {
    685		pr_err("ti-sci-init-clocks failed.\n");
    686		return ret;
    687	}
    688
    689	return of_clk_add_hw_provider(np, sci_clk_get, provider);
    690}
    691
    692/**
    693 * ti_sci_clk_remove - Remove TI SCI clock device
    694 * @pdev: platform device pointer for the device to be removed
    695 *
    696 * Removes the TI SCI device. Unregisters the clock provider registered
    697 * via common clock framework. Any memory allocated for the device will
    698 * be free'd silently via the devm framework. Returns 0 always.
    699 */
    700static int ti_sci_clk_remove(struct platform_device *pdev)
    701{
    702	of_clk_del_provider(pdev->dev.of_node);
    703
    704	return 0;
    705}
    706
    707static struct platform_driver ti_sci_clk_driver = {
    708	.probe = ti_sci_clk_probe,
    709	.remove = ti_sci_clk_remove,
    710	.driver = {
    711		.name = "ti-sci-clk",
    712		.of_match_table = of_match_ptr(ti_sci_clk_of_match),
    713	},
    714};
    715module_platform_driver(ti_sci_clk_driver);
    716
    717MODULE_LICENSE("GPL v2");
    718MODULE_DESCRIPTION("TI System Control Interface(SCI) Clock driver");
    719MODULE_AUTHOR("Tero Kristo");
    720MODULE_ALIAS("platform:ti-sci-clk");