4,436
社区成员
发帖
与我相关
我的任务
分享
linux-2.6.21.5/arch/arm/plat-s3c24xx/clock.c
/* Clock API calls */
struct clk *(struct device *dev, const char *id)
{
struct clk *p;
struct clk *clk = ERR_PTR(-ENOENT);
int idno;
if (dev == NULL || dev->bus != &platform_bus_type)
idno = -1;
else
idno = to_platform_device(dev)->id;
mutex_lock(&clocks_mutex);
list_for_each_entry(p, & clocks, list) {
if (p->id == idno &&
strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
/* check for the case where a device was supplied, but the
* clock that was being searched for is not device specific */
if (IS_ERR(clk)) {
list_for_each_entry(p, &clocks, list) {
if (p->id == -1 && strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
}
mutex_unlock(&clocks_mutex);
return clk;
}
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
说白了define list_for_each_entry 就是一个for循环。。。。
struct clk clk_xtal = {
.name = "xtal",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk {
struct list_head node;
const char *name; /* unique clock name */
const char *function; /* function of the clock */
struct device *dev; /* device associated with function */
unsigned long rate_hz;
struct clk *parent;
u32 pmc_mask;
void (*mode)(struct clk *, int);
unsigned id:2; /* PCK0..3, or 32k/main/a/b */
unsigned type; /* clock type */
u16 users;
};
static struct clk isi_clk = {
.name = "isi_clk",
.pmc_mask = 1 << AT91CAP9_ID_ISI,
.type = CLK_TYPE_PERIPHERAL,
};
static void __clk_enable(struct clk *clk)
{
if (clk->parent)
__clk_enable(clk->parent);
if (clk->users++ == 0 && clk->mode)
clk->mode(clk, 1);
}
int clk_enable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clk_lock, flags);
__clk_enable(clk);
spin_unlock_irqrestore(&clk_lock, flags);
return 0;
}
EXPORT_SYMBOL(clk_enable);
/* Register a new clock */
int __init clk_register(struct clk *clk)
{
if (clk_is_peripheral(clk)) {
clk->parent = &mck;
clk->mode = pmc_periph_mode;
list_add_tail(&clk->node, &clocks);
}
else if (clk_is_sys(clk)) {
clk->parent = &mck;
clk->mode = pmc_sys_mode;
list_add_tail(&clk->node, &clocks);
}
#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
else if (clk_is_programmable(clk)) {
clk->mode = pmc_sys_mode;
init_programmable_clock(clk);
list_add_tail(&clk->node, &clocks);
}
#endif
return 0;
}
/*
* Several unused clocks may be active. Turn them off.
*/
static int __init at91_clock_reset(void)
{
unsigned long pcdr = 0;
unsigned long scdr = 0;
struct clk *clk;
list_for_each_entry(clk, &clocks, node) {
if (clk->users > 0)
continue;
if (clk->mode == pmc_periph_mode)
pcdr |= clk->pmc_mask;
if (clk->mode == pmc_sys_mode)
scdr |= clk->pmc_mask;
pr_debug("Clocks: disable unused %s\n", clk->name);
}
at91_sys_write(AT91_PMC_PCDR, pcdr);
at91_sys_write(AT91_PMC_SCDR, scdr);
return 0;
}
late_initcall(at91_clock_reset);
static void pmc_periph_mode(struct clk *clk, int is_on)
{
if (is_on)
at91_sys_write(AT91_PMC_PCER, clk->pmc_mask);
else
at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
}