alistair23-linux/include/linux/amba/bus.h
Russell King 7cfe249475 ARM: AMBA: Add pclk support to AMBA bus infrastructure
Some platforms gate the pclk (APB - the bus - clock) to the peripherals
for power saving, along with the functional clock.  When devices are
accessed without pclk enabled, the kernel will oops.

This gives them two options:

1. Leave all clocks on all the time.
2. Attempt to gate pclk along with the functional clock.

(With some hardware, pclk and the functional clock are gated by a single
bit in a register.)

(1) has the disadvantage that it causes increased power usage, which is
bad news for battery operated devices.  (2) can lead to kernel oops if
registers are accessed without the functional clock being enabled.

So, introduce the apb_pclk signal in such a way existing drivers don't
need to be updated.  Essentially, this means we guarantee that:

1. pclk will be enabled whenever the driver is bound to a device -
   from probe() to remove() time.
2. pclk will also be enabled when reading the primecell IDs from the device.

In order to allow drivers to be incrementally updated to achieve greater
power savings, we provide two additional calls to allow drivers to
manage the pclk - amba_pclk_enable()/amba_pclk_disable().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2010-07-31 13:07:27 +01:00

79 lines
2.2 KiB
C

/*
* linux/include/amba/bus.h
*
* This device type deals with ARM PrimeCells and anything else that
* presents a proper CID (0xB105F00D) at the end of the I/O register
* region or that is derived from a PrimeCell.
*
* Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
*
* 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.
*/
#ifndef ASMARM_AMBA_H
#define ASMARM_AMBA_H
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/resource.h>
#define AMBA_NR_IRQS 2
struct clk;
struct amba_device {
struct device dev;
struct resource res;
struct clk *pclk;
u64 dma_mask;
unsigned int periphid;
unsigned int irq[AMBA_NR_IRQS];
};
struct amba_id {
unsigned int id;
unsigned int mask;
void *data;
};
struct amba_driver {
struct device_driver drv;
int (*probe)(struct amba_device *, struct amba_id *);
int (*remove)(struct amba_device *);
void (*shutdown)(struct amba_device *);
int (*suspend)(struct amba_device *, pm_message_t);
int (*resume)(struct amba_device *);
struct amba_id *id_table;
};
enum amba_vendor {
AMBA_VENDOR_ARM = 0x41,
AMBA_VENDOR_ST = 0x80,
};
#define amba_get_drvdata(d) dev_get_drvdata(&d->dev)
#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p)
int amba_driver_register(struct amba_driver *);
void amba_driver_unregister(struct amba_driver *);
int amba_device_register(struct amba_device *, struct resource *);
void amba_device_unregister(struct amba_device *);
struct amba_device *amba_find_device(const char *, struct device *, unsigned int, unsigned int);
int amba_request_regions(struct amba_device *, const char *);
void amba_release_regions(struct amba_device *);
#define amba_pclk_enable(d) \
(IS_ERR((d)->pclk) ? 0 : clk_enable((d)->pclk))
#define amba_pclk_disable(d) \
do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
#define amba_config(d) (((d)->periphid >> 24) & 0xff)
#define amba_rev(d) (((d)->periphid >> 20) & 0x0f)
#define amba_manf(d) (((d)->periphid >> 12) & 0xff)
#define amba_part(d) ((d)->periphid & 0xfff)
#endif