Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
dbdf6ff5
Commit
dbdf6ff5
authored
Dec 31, 2013
by
Mike Turquette
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'clk-next-unregister' into clk-next
Conflicts: drivers/clk/clk.c
parents
391e3903
9ffe29d7
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
235 additions
and
19 deletions
+235
-19
arch/arm/include/asm/clkdev.h
arch/arm/include/asm/clkdev.h
+2
-0
arch/blackfin/include/asm/clkdev.h
arch/blackfin/include/asm/clkdev.h
+2
-0
arch/mips/include/asm/clkdev.h
arch/mips/include/asm/clkdev.h
+2
-0
arch/sh/include/asm/clkdev.h
arch/sh/include/asm/clkdev.h
+2
-0
drivers/clk/clk.c
drivers/clk/clk.c
+174
-11
drivers/clk/clk.h
drivers/clk/clk.h
+16
-0
drivers/clk/clkdev.c
drivers/clk/clkdev.c
+10
-2
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/omap3isp/isp.c
+16
-6
drivers/media/platform/omap3isp/isp.h
drivers/media/platform/omap3isp/isp.h
+1
-0
include/linux/clk-private.h
include/linux/clk-private.h
+5
-0
include/linux/clkdev.h
include/linux/clkdev.h
+5
-0
No files found.
arch/arm/include/asm/clkdev.h
View file @
dbdf6ff5
...
...
@@ -14,12 +14,14 @@
#include <linux/slab.h>
#ifndef CONFIG_COMMON_CLK
#ifdef CONFIG_HAVE_MACH_CLKDEV
#include <mach/clkdev.h>
#else
#define __clk_get(clk) ({ 1; })
#define __clk_put(clk) do { } while (0)
#endif
#endif
static
inline
struct
clk_lookup_alloc
*
__clkdev_alloc
(
size_t
size
)
{
...
...
arch/blackfin/include/asm/clkdev.h
View file @
dbdf6ff5
...
...
@@ -8,7 +8,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
return
kzalloc
(
size
,
GFP_KERNEL
);
}
#ifndef CONFIG_COMMON_CLK
#define __clk_put(clk)
#define __clk_get(clk) ({ 1; })
#endif
#endif
arch/mips/include/asm/clkdev.h
View file @
dbdf6ff5
...
...
@@ -14,8 +14,10 @@
#include <linux/slab.h>
#ifndef CONFIG_COMMON_CLK
#define __clk_get(clk) ({ 1; })
#define __clk_put(clk) do { } while (0)
#endif
static
inline
struct
clk_lookup_alloc
*
__clkdev_alloc
(
size_t
size
)
{
...
...
arch/sh/include/asm/clkdev.h
View file @
dbdf6ff5
...
...
@@ -25,7 +25,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
return
kzalloc
(
size
,
GFP_KERNEL
);
}
#ifndef CONFIG_COMMON_CLK
#define __clk_put(clk)
#define __clk_get(clk) ({ 1; })
#endif
#endif
/* __CLKDEV_H__ */
drivers/clk/clk.c
View file @
dbdf6ff5
...
...
@@ -21,6 +21,8 @@
#include <linux/init.h>
#include <linux/sched.h>
#include "clk.h"
static
DEFINE_SPINLOCK
(
enable_lock
);
static
DEFINE_MUTEX
(
prepare_lock
);
...
...
@@ -350,6 +352,21 @@ static int clk_debug_register(struct clk *clk)
return
ret
;
}
/**
* clk_debug_unregister - remove a clk node from the debugfs clk tree
* @clk: the clk being removed from the debugfs clk tree
*
* Dynamically removes a clk and all it's children clk nodes from the
* debugfs clk tree if clk->dentry points to debugfs created by
* clk_debug_register in __clk_init.
*
* Caller must hold prepare_lock.
*/
static
void
clk_debug_unregister
(
struct
clk
*
clk
)
{
debugfs_remove_recursive
(
clk
->
dentry
);
}
/**
* clk_debug_reparent - reparent clk node in the debugfs clk tree
* @clk: the clk being reparented
...
...
@@ -440,6 +457,9 @@ static inline int clk_debug_register(struct clk *clk) { return 0; }
static
inline
void
clk_debug_reparent
(
struct
clk
*
clk
,
struct
clk
*
new_parent
)
{
}
static
inline
void
clk_debug_unregister
(
struct
clk
*
clk
)
{
}
#endif
/* caller must hold prepare_lock */
...
...
@@ -1861,6 +1881,7 @@ int __clk_init(struct device *dev, struct clk *clk)
if
(
clk
->
ops
->
init
)
clk
->
ops
->
init
(
clk
->
hw
);
kref_init
(
&
clk
->
ref
);
out:
clk_prepare_unlock
();
...
...
@@ -1896,6 +1917,10 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
clk
->
flags
=
hw
->
init
->
flags
;
clk
->
parent_names
=
hw
->
init
->
parent_names
;
clk
->
num_parents
=
hw
->
init
->
num_parents
;
if
(
dev
&&
dev
->
driver
)
clk
->
owner
=
dev
->
driver
->
owner
;
else
clk
->
owner
=
NULL
;
ret
=
__clk_init
(
dev
,
clk
);
if
(
ret
)
...
...
@@ -1916,6 +1941,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk)
goto
fail_name
;
}
clk
->
ops
=
hw
->
init
->
ops
;
if
(
dev
&&
dev
->
driver
)
clk
->
owner
=
dev
->
driver
->
owner
;
clk
->
hw
=
hw
;
clk
->
flags
=
hw
->
init
->
flags
;
clk
->
num_parents
=
hw
->
init
->
num_parents
;
...
...
@@ -1990,13 +2017,104 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL
(
clk_register
);
/*
* Free memory allocated for a clock.
* Caller must hold prepare_lock.
*/
static
void
__clk_release
(
struct
kref
*
ref
)
{
struct
clk
*
clk
=
container_of
(
ref
,
struct
clk
,
ref
);
int
i
=
clk
->
num_parents
;
kfree
(
clk
->
parents
);
while
(
--
i
>=
0
)
kfree
(
clk
->
parent_names
[
i
]);
kfree
(
clk
->
parent_names
);
kfree
(
clk
->
name
);
kfree
(
clk
);
}
/*
* Empty clk_ops for unregistered clocks. These are used temporarily
* after clk_unregister() was called on a clock and until last clock
* consumer calls clk_put() and the struct clk object is freed.
*/
static
int
clk_nodrv_prepare_enable
(
struct
clk_hw
*
hw
)
{
return
-
ENXIO
;
}
static
void
clk_nodrv_disable_unprepare
(
struct
clk_hw
*
hw
)
{
WARN_ON_ONCE
(
1
);
}
static
int
clk_nodrv_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
return
-
ENXIO
;
}
static
int
clk_nodrv_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
return
-
ENXIO
;
}
static
const
struct
clk_ops
clk_nodrv_ops
=
{
.
enable
=
clk_nodrv_prepare_enable
,
.
disable
=
clk_nodrv_disable_unprepare
,
.
prepare
=
clk_nodrv_prepare_enable
,
.
unprepare
=
clk_nodrv_disable_unprepare
,
.
set_rate
=
clk_nodrv_set_rate
,
.
set_parent
=
clk_nodrv_set_parent
,
};
/**
* clk_unregister - unregister a currently registered clock
* @clk: clock to unregister
*
* Currently unimplemented.
*/
void
clk_unregister
(
struct
clk
*
clk
)
{}
void
clk_unregister
(
struct
clk
*
clk
)
{
unsigned
long
flags
;
if
(
!
clk
||
WARN_ON_ONCE
(
IS_ERR
(
clk
)))
return
;
clk_prepare_lock
();
if
(
clk
->
ops
==
&
clk_nodrv_ops
)
{
pr_err
(
"%s: unregistered clock: %s
\n
"
,
__func__
,
clk
->
name
);
goto
out
;
}
/*
* Assign empty clock ops for consumers that might still hold
* a reference to this clock.
*/
flags
=
clk_enable_lock
();
clk
->
ops
=
&
clk_nodrv_ops
;
clk_enable_unlock
(
flags
);
if
(
!
hlist_empty
(
&
clk
->
children
))
{
struct
clk
*
child
;
/* Reparent all children to the orphan list. */
hlist_for_each_entry
(
child
,
&
clk
->
children
,
child_node
)
clk_set_parent
(
child
,
NULL
);
}
clk_debug_unregister
(
clk
);
hlist_del_init
(
&
clk
->
child_node
);
if
(
clk
->
prepare_count
)
pr_warn
(
"%s: unregistering prepared clock: %s
\n
"
,
__func__
,
clk
->
name
);
kref_put
(
&
clk
->
ref
,
__clk_release
);
out:
clk_prepare_unlock
();
}
EXPORT_SYMBOL_GPL
(
clk_unregister
);
static
void
devm_clk_release
(
struct
device
*
dev
,
void
*
res
)
...
...
@@ -2056,6 +2174,31 @@ void devm_clk_unregister(struct device *dev, struct clk *clk)
}
EXPORT_SYMBOL_GPL
(
devm_clk_unregister
);
/*
* clkdev helpers
*/
int
__clk_get
(
struct
clk
*
clk
)
{
if
(
clk
&&
!
try_module_get
(
clk
->
owner
))
return
0
;
kref_get
(
&
clk
->
ref
);
return
1
;
}
void
__clk_put
(
struct
clk
*
clk
)
{
if
(
WARN_ON_ONCE
(
IS_ERR
(
clk
)))
return
;
clk_prepare_lock
();
kref_put
(
&
clk
->
ref
,
__clk_release
);
clk_prepare_unlock
();
if
(
clk
)
module_put
(
clk
->
owner
);
}
/*** clk rate change notifiers ***/
/**
...
...
@@ -2196,7 +2339,18 @@ static const struct of_device_id __clk_of_table_sentinel
__used
__section
(
__clk_of_table_end
);
static
LIST_HEAD
(
of_clk_providers
);
static
DEFINE_MUTEX
(
of_clk_lock
);
static
DEFINE_MUTEX
(
of_clk_mutex
);
/* of_clk_provider list locking helpers */
void
of_clk_lock
(
void
)
{
mutex_lock
(
&
of_clk_mutex
);
}
void
of_clk_unlock
(
void
)
{
mutex_unlock
(
&
of_clk_mutex
);
}
struct
clk
*
of_clk_src_simple_get
(
struct
of_phandle_args
*
clkspec
,
void
*
data
)
...
...
@@ -2240,9 +2394,9 @@ int of_clk_add_provider(struct device_node *np,
cp
->
data
=
data
;
cp
->
get
=
clk_src_get
;
mutex_lock
(
&
of_clk_
lock
);
mutex_lock
(
&
of_clk_
mutex
);
list_add
(
&
cp
->
link
,
&
of_clk_providers
);
mutex_unlock
(
&
of_clk_
lock
);
mutex_unlock
(
&
of_clk_
mutex
);
pr_debug
(
"Added clock from %s
\n
"
,
np
->
full_name
);
return
0
;
...
...
@@ -2257,7 +2411,7 @@ void of_clk_del_provider(struct device_node *np)
{
struct
of_clk_provider
*
cp
;
mutex_lock
(
&
of_clk_
lock
);
mutex_lock
(
&
of_clk_
mutex
);
list_for_each_entry
(
cp
,
&
of_clk_providers
,
link
)
{
if
(
cp
->
node
==
np
)
{
list_del
(
&
cp
->
link
);
...
...
@@ -2266,24 +2420,33 @@ void of_clk_del_provider(struct device_node *np)
break
;
}
}
mutex_unlock
(
&
of_clk_
lock
);
mutex_unlock
(
&
of_clk_
mutex
);
}
EXPORT_SYMBOL_GPL
(
of_clk_del_provider
);
struct
clk
*
of_clk_get_from_provider
(
struct
of_phandle_args
*
clkspec
)
struct
clk
*
__
of_clk_get_from_provider
(
struct
of_phandle_args
*
clkspec
)
{
struct
of_clk_provider
*
provider
;
struct
clk
*
clk
=
ERR_PTR
(
-
ENOENT
);
/* Check if we have such a provider in our array */
mutex_lock
(
&
of_clk_lock
);
list_for_each_entry
(
provider
,
&
of_clk_providers
,
link
)
{
if
(
provider
->
node
==
clkspec
->
np
)
clk
=
provider
->
get
(
clkspec
,
provider
->
data
);
if
(
!
IS_ERR
(
clk
))
break
;
}
mutex_unlock
(
&
of_clk_lock
);
return
clk
;
}
struct
clk
*
of_clk_get_from_provider
(
struct
of_phandle_args
*
clkspec
)
{
struct
clk
*
clk
;
mutex_lock
(
&
of_clk_mutex
);
clk
=
__of_clk_get_from_provider
(
clkspec
);
mutex_unlock
(
&
of_clk_mutex
);
return
clk
;
}
...
...
drivers/clk/clk.h
0 → 100644
View file @
dbdf6ff5
/*
* linux/drivers/clk/clk.h
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct
clk
*
__of_clk_get_from_provider
(
struct
of_phandle_args
*
clkspec
);
void
of_clk_lock
(
void
);
void
of_clk_unlock
(
void
);
#endif
drivers/clk/clkdev.c
View file @
dbdf6ff5
...
...
@@ -21,6 +21,8 @@
#include <linux/clkdev.h>
#include <linux/of.h>
#include "clk.h"
static
LIST_HEAD
(
clocks
);
static
DEFINE_MUTEX
(
clocks_mutex
);
...
...
@@ -39,7 +41,13 @@ struct clk *of_clk_get(struct device_node *np, int index)
if
(
rc
)
return
ERR_PTR
(
rc
);
clk
=
of_clk_get_from_provider
(
&
clkspec
);
of_clk_lock
();
clk
=
__of_clk_get_from_provider
(
&
clkspec
);
if
(
!
IS_ERR
(
clk
)
&&
!
__clk_get
(
clk
))
clk
=
ERR_PTR
(
-
ENOENT
);
of_clk_unlock
();
of_node_put
(
clkspec
.
np
);
return
clk
;
}
...
...
@@ -157,7 +165,7 @@ struct clk *clk_get(struct device *dev, const char *con_id)
if
(
dev
)
{
clk
=
of_clk_get_by_name
(
dev
->
of_node
,
con_id
);
if
(
!
IS_ERR
(
clk
)
&&
__clk_get
(
clk
)
)
if
(
!
IS_ERR
(
clk
))
return
clk
;
}
...
...
drivers/media/platform/omap3isp/isp.c
View file @
dbdf6ff5
...
...
@@ -290,9 +290,11 @@ static int isp_xclk_init(struct isp_device *isp)
struct
clk_init_data
init
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
isp
->
xclks
);
++
i
)
isp
->
xclks
[
i
].
clk
=
ERR_PTR
(
-
EINVAL
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
isp
->
xclks
);
++
i
)
{
struct
isp_xclk
*
xclk
=
&
isp
->
xclks
[
i
];
struct
clk
*
clk
;
xclk
->
isp
=
isp
;
xclk
->
id
=
i
==
0
?
ISP_XCLK_A
:
ISP_XCLK_B
;
...
...
@@ -305,10 +307,15 @@ static int isp_xclk_init(struct isp_device *isp)
init
.
num_parents
=
1
;
xclk
->
hw
.
init
=
&
init
;
clk
=
devm_clk_register
(
isp
->
dev
,
&
xclk
->
hw
);
if
(
IS_ERR
(
clk
))
return
PTR_ERR
(
clk
);
/*
* The first argument is NULL in order to avoid circular
* reference, as this driver takes reference on the
* sensor subdevice modules and the sensors would take
* reference on this module through clk_get().
*/
xclk
->
clk
=
clk_register
(
NULL
,
&
xclk
->
hw
);
if
(
IS_ERR
(
xclk
->
clk
))
return
PTR_ERR
(
xclk
->
clk
);
if
(
pdata
->
xclks
[
i
].
con_id
==
NULL
&&
pdata
->
xclks
[
i
].
dev_id
==
NULL
)
...
...
@@ -320,7 +327,7 @@ static int isp_xclk_init(struct isp_device *isp)
xclk
->
lookup
->
con_id
=
pdata
->
xclks
[
i
].
con_id
;
xclk
->
lookup
->
dev_id
=
pdata
->
xclks
[
i
].
dev_id
;
xclk
->
lookup
->
clk
=
clk
;
xclk
->
lookup
->
clk
=
xclk
->
clk
;
clkdev_add
(
xclk
->
lookup
);
}
...
...
@@ -335,6 +342,9 @@ static void isp_xclk_cleanup(struct isp_device *isp)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
isp
->
xclks
);
++
i
)
{
struct
isp_xclk
*
xclk
=
&
isp
->
xclks
[
i
];
if
(
!
IS_ERR
(
xclk
->
clk
))
clk_unregister
(
xclk
->
clk
);
if
(
xclk
->
lookup
)
clkdev_drop
(
xclk
->
lookup
);
}
...
...
drivers/media/platform/omap3isp/isp.h
View file @
dbdf6ff5
...
...
@@ -135,6 +135,7 @@ struct isp_xclk {
struct
isp_device
*
isp
;
struct
clk_hw
hw
;
struct
clk_lookup
*
lookup
;
struct
clk
*
clk
;
enum
isp_xclk_id
id
;
spinlock_t
lock
;
/* Protects enabled and divider */
...
...
include/linux/clk-private.h
View file @
dbdf6ff5
...
...
@@ -12,6 +12,7 @@
#define __LINUX_CLK_PRIVATE_H
#include <linux/clk-provider.h>
#include <linux/kref.h>
#include <linux/list.h>
/*
...
...
@@ -25,10 +26,13 @@
#ifdef CONFIG_COMMON_CLK
struct
module
;
struct
clk
{
const
char
*
name
;
const
struct
clk_ops
*
ops
;
struct
clk_hw
*
hw
;
struct
module
*
owner
;
struct
clk
*
parent
;
const
char
**
parent_names
;
struct
clk
**
parents
;
...
...
@@ -48,6 +52,7 @@ struct clk {
#ifdef CONFIG_DEBUG_FS
struct
dentry
*
dentry
;
#endif
struct
kref
ref
;
};
/*
...
...
include/linux/clkdev.h
View file @
dbdf6ff5
...
...
@@ -43,4 +43,9 @@ int clk_add_alias(const char *, const char *, char *, struct device *);
int
clk_register_clkdev
(
struct
clk
*
,
const
char
*
,
const
char
*
,
...);
int
clk_register_clkdevs
(
struct
clk
*
,
struct
clk_lookup
*
,
size_t
);
#ifdef CONFIG_COMMON_CLK
int
__clk_get
(
struct
clk
*
clk
);
void
__clk_put
(
struct
clk
*
clk
);
#endif
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment