* [PATCH 6/6] nvram: Shrink our zlib_deflate workspace from 268K to 24K
From: Jim Keniston @ 2010-11-14 4:15 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20101114041510.9457.92921.stgit@localhost.localdomain>
Exploit zlib_deflate_workspacesize2() to create a much smaller
zlib_deflate workspace when capturing oops/panic reports to NVRAM.
Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
---
arch/powerpc/platforms/pseries/nvram.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 8e5ed74..6409cb6 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -17,7 +17,6 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/kmsg_dump.h>
#include <linux/zlib.h>
@@ -94,6 +93,8 @@ static struct oops_parition_data {
} *little_oops_buf;
#define COMPR_LEVEL 6
+#define WINDOW_BITS 12
+#define MEM_LEVEL 4
static struct z_stream_s stream;
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
@@ -408,7 +409,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
big_oops_buf_sz = (little_oops_buf_sz * 100) / 45;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (big_oops_buf) {
- stream.workspace = vmalloc(zlib_deflate_workspacesize());
+ stream.workspace = kmalloc(zlib_deflate_workspacesize2(
+ WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
if (!stream.workspace) {
pr_err("nvram: No memory for compression workspace; "
"skipping compression of %s partition data\n",
@@ -427,7 +429,7 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
kfree(little_oops_buf);
kfree(big_oops_buf);
- vfree(stream.workspace);
+ kfree(stream.workspace);
}
}
@@ -625,7 +627,8 @@ static int nvram_compress(const void *in, void *out, size_t inlen,
int err, ret;
ret = -EIO;
- err = zlib_deflateInit(&stream, COMPR_LEVEL);
+ err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
+ MEM_LEVEL, Z_DEFAULT_STRATEGY);
if (err != Z_OK)
goto error;
^ permalink raw reply related
* [PATCH 5/6] nvram: Slim down zlib_deflate workspace when possible
From: Jim Keniston @ 2010-11-14 4:15 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20101114041510.9457.92921.stgit@localhost.localdomain>
Instead of always creating a huge (268K) deflate_workspace with the
maximum compression parameters (windowBits=15, memLevel=8), allow the
caller to obtain a smaller workspace (24K in our case) by specifying
smaller parameter values -- via zlib_deflate_workspacesize2(). In our
case, a small workspace is a win because our choices are to allocate
the workspace when we need it (i.e., during an oops or panic) or
allocate it at boot time. (We do the latter.)
Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
---
include/linux/zlib.h | 14 ++++++++++++--
lib/zlib_deflate/deflate.c | 33 ++++++++++++++++++++++++++++++++-
lib/zlib_deflate/deflate_syms.c | 1 +
lib/zlib_deflate/defutil.h | 17 +++++++++++++----
4 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/include/linux/zlib.h b/include/linux/zlib.h
index 40c49cb..3f15036 100644
--- a/include/linux/zlib.h
+++ b/include/linux/zlib.h
@@ -179,11 +179,21 @@ typedef z_stream *z_streamp;
/* basic functions */
+extern int zlib_deflate_workspacesize2 (int windowBits, int memLevel);
+/*
+ Returns the number of bytes that needs to be allocated for a per-
+ stream workspace with the specified parameters. A pointer to this
+ number of bytes should be returned in stream->workspace before
+ calling zlib_deflateInit2(); and the windowBits and memLevel
+ parameters passed to zlib_deflateInit2() must not exceed those
+ passed here.
+*/
+
extern int zlib_deflate_workspacesize (void);
/*
Returns the number of bytes that needs to be allocated for a per-
- stream workspace. A pointer to this number of bytes should be
- returned in stream->workspace before calling zlib_deflateInit().
+ stream workspace with the default (large) windowBits and memLevel
+ parameters.
*/
/*
diff --git a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c
index 46a31e5..cdb207a 100644
--- a/lib/zlib_deflate/deflate.c
+++ b/lib/zlib_deflate/deflate.c
@@ -176,6 +176,7 @@ int zlib_deflateInit2(
deflate_state *s;
int noheader = 0;
deflate_workspace *mem;
+ char *next;
ush *overlay;
/* We overlay pending_buf and d_buf+l_buf. This works since the average
@@ -199,6 +200,21 @@ int zlib_deflateInit2(
strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
return Z_STREAM_ERROR;
}
+
+ /*
+ * Direct the workspace's pointers to the chunks that were allocated
+ * along with the deflate_workspace struct.
+ */
+ next = (char *) mem;
+ next += sizeof(*mem);
+ mem->window_memory = (Byte *) next;
+ next += zlib_deflate_window_memsize(windowBits);
+ mem->prev_memory = (Pos *) next;
+ next += zlib_deflate_prev_memsize(windowBits);
+ mem->head_memory = (Pos *) next;
+ next += zlib_deflate_head_memsize(memLevel);
+ mem->overlay_memory = next;
+
s = (deflate_state *) &(mem->deflate_memory);
strm->state = (struct internal_state *)s;
s->strm = strm;
@@ -1249,5 +1265,20 @@ static block_state deflate_slow(
int zlib_deflate_workspacesize(void)
{
- return sizeof(deflate_workspace);
+ return zlib_deflate_workspacesize2(MAX_WBITS, MAX_MEM_LEVEL);
+}
+
+int zlib_deflate_workspacesize2(int windowBits, int memLevel)
+{
+ if (windowBits < 0) /* undocumented feature: suppress zlib header */
+ windowBits = -windowBits;
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL ||
+ windowBits < 9 || windowBits > 15)
+ return -1;
+
+ return sizeof(deflate_workspace)
+ + zlib_deflate_window_memsize(windowBits)
+ + zlib_deflate_prev_memsize(windowBits)
+ + zlib_deflate_head_memsize(memLevel)
+ + zlib_deflate_overlay_memsize(memLevel);
}
diff --git a/lib/zlib_deflate/deflate_syms.c b/lib/zlib_deflate/deflate_syms.c
index ccfe25f..cdf1cdd 100644
--- a/lib/zlib_deflate/deflate_syms.c
+++ b/lib/zlib_deflate/deflate_syms.c
@@ -11,6 +11,7 @@
#include <linux/zlib.h>
EXPORT_SYMBOL(zlib_deflate_workspacesize);
+EXPORT_SYMBOL(zlib_deflate_workspacesize2);
EXPORT_SYMBOL(zlib_deflate);
EXPORT_SYMBOL(zlib_deflateInit2);
EXPORT_SYMBOL(zlib_deflateEnd);
diff --git a/lib/zlib_deflate/defutil.h b/lib/zlib_deflate/defutil.h
index 6b15a90..b640b64 100644
--- a/lib/zlib_deflate/defutil.h
+++ b/lib/zlib_deflate/defutil.h
@@ -241,12 +241,21 @@ typedef struct deflate_state {
typedef struct deflate_workspace {
/* State memory for the deflator */
deflate_state deflate_memory;
- Byte window_memory[2 * (1 << MAX_WBITS)];
- Pos prev_memory[1 << MAX_WBITS];
- Pos head_memory[1 << (MAX_MEM_LEVEL + 7)];
- char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)];
+ Byte *window_memory;
+ Pos *prev_memory;
+ Pos *head_memory;
+ char *overlay_memory;
} deflate_workspace;
+#define zlib_deflate_window_memsize(windowBits) \
+ (2 * (1 << (windowBits)) * sizeof(Byte))
+#define zlib_deflate_prev_memsize(windowBits) \
+ ((1 << (windowBits)) * sizeof(Pos))
+#define zlib_deflate_head_memsize(memLevel) \
+ ((1 << ((memLevel)+7)) * sizeof(Pos))
+#define zlib_deflate_overlay_memsize(memLevel) \
+ ((1 << ((memLevel)+6)) * (sizeof(ush)+2))
+
/* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf.
*/
^ permalink raw reply related
* Re: [RFC PATCH 0/6] nvram: Capture oops/panic reports in NVRAM
From: Jim Keniston @ 2010-11-14 4:36 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20101114041510.9457.92921.stgit@localhost.localdomain>
On Sat, 2010-11-13 at 20:15 -0800, Jim Keniston wrote:
> This patch series enables p Series systems to capture oops and panic
> reports from the printk buffer into NVRAM, where they can be examined
> after reboot using the nvram command.
>
Here's a patch to the nvram command to add --unzip and --ascii options,
for examination of oops/panic reports captured in ibm,oops-log or
ibm,rtas-log.
The nvram command is part of powerpc-utils --
git://powerpc-utils.git.sourceforge.net/gitroot/powerpc-utils/powerpc-utils
You can build it using
cc nvram.c -ldl -lz -o nvram
BTW, as far as I can tell, the zlib_deflate code in the kernel can't
produce the header that the gunzip command wants -- hence the reliance
on libz in the nvram command.
Jim
---
src/nvram.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 136 insertions(+), 0 deletions(-)
diff --git a/src/nvram.c b/src/nvram.c
index d25e073..e00ae12 100644
--- a/src/nvram.c
+++ b/src/nvram.c
@@ -43,6 +43,7 @@
#include <glob.h>
#include <getopt.h>
#include <inttypes.h>
+#include <zlib.h>
#include "nvram.h"
@@ -62,6 +63,8 @@ static struct option long_options[] = {
{"print-event-scan", no_argument, NULL, 'E'},
{"partitions", no_argument, NULL, 'P'},
{"dump", required_argument, NULL, 'd'},
+ {"ascii", required_argument, NULL, 'a'},
+ {"unzip", required_argument, NULL, 'z'},
{"nvram-file", required_argument, NULL, 'n'},
{"nvram-size", required_argument, NULL, 's'},
{"update-config", required_argument, NULL, 'u'},
@@ -99,6 +102,10 @@ help(void)
" print NVRAM paritition header info\n"
" --dump <name>\n"
" raw dump of partition (use --partitions to see names)\n"
+ " --ascii <name>\n"
+ " print partition contents as ASCII text\n"
+ " --unzip <name>\n"
+ " decompress and print compressed data from partition\n"
" --nvram-file <path>\n"
" specify alternate nvram data file (default is /dev/nvram)\n"
" --nvram-size\n"
@@ -1189,6 +1196,121 @@ dump_raw_partition(struct nvram *nvram, char *name)
}
/**
+ * dump_ascii_partition
+ * @brief ASCII data dump of a partition, excluding header
+ *
+ * @param nvram nvram struct containing partition
+ * @param name name of partition to dump
+ * @return 0 on success, !0 otherwise
+ *
+ * Partition subheaders, if any, are dumped along with the rest of the data.
+ * We substitute periods for unprintable characters.
+ */
+int
+dump_ascii_partition(struct nvram *nvram, char *name)
+{
+ struct partition_header *phead;
+ char *start, *end, *c;
+
+ phead = nvram_find_partition(nvram, 0, name, NULL);
+ if (!phead) {
+ err_msg("there is no %s partition!\n", name);
+ return -1;
+ }
+
+ start = (char*) phead;
+ end = start + phead->length * NVRAM_BLOCK_SIZE;
+ start += sizeof(*phead); /* Skip partition header. */
+ for (c = start; c < end; c++) {
+ if (isprint(*c) || isspace(*c))
+ putchar(*c);
+ else
+ putchar('.');
+ }
+ /* Always end with a newline.*/
+ putchar('\n');
+ return 0;
+}
+
+int
+dump_zipped_text(char *zipped_text, unsigned int zipped_length)
+{
+ z_stream strm;
+ int result;
+ char unzipped_text[4096];
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = zipped_length;
+ strm.next_in = zipped_text;
+ result = inflateInit(&strm);
+ if (result != Z_OK) {
+ err_msg("can't decompress text: inflateInit() returned %d\n", result);
+ return -1;
+ }
+
+ do {
+ strm.avail_out = 4096;
+ strm.next_out = unzipped_text;
+ result = inflate(&strm, Z_NO_FLUSH);
+ switch (result) {
+ case Z_STREAM_ERROR:
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ err_msg("can't decompress text: inflate() returned %d\n", result);
+ (void) inflateEnd(&strm);
+ return -1;
+ }
+ if (fwrite(unzipped_text, 4096 - strm.avail_out, 1, stdout) != 1) {
+ err_msg("can't decompress text: fwrite() failed\n");
+ (void) inflateEnd(&strm);
+ return -1;
+ }
+ } while (strm.avail_out == 0);
+
+ (void) inflateEnd(&strm);
+ return 0;
+}
+
+/**
+ * unzip_partition
+ * @brief Uncompress and print compressed data from a partition.
+ *
+ * @param nvram nvram struct containing partition
+ * @param name name of partition to dump
+ * @return 0 on success, !0 otherwise
+ */
+int
+unzip_partition(struct nvram *nvram, char *name)
+{
+ struct partition_header *phead;
+ char *start, *next;
+ unsigned short zipped_length;
+
+ phead = nvram_find_partition(nvram, 0, name, NULL);
+ if (!phead) {
+ err_msg("there is no %s partition!\n", name);
+ return -1;
+ }
+
+ start = (char*) phead;
+ next = start + sizeof(*phead); /* Skip partition header. */
+ next += sizeof(struct err_log_info); /* Skip sub-header. */
+ zipped_length = *((unsigned short*) next);
+ next += sizeof(unsigned short); /* Skip compressed length. */
+
+ if ((next-start) + zipped_length > phead->length * NVRAM_BLOCK_SIZE) {
+ err_msg("bogus size for compressed data in partition %s: %u\n", name,
+ zipped_length);
+ return -1;
+ }
+
+ return dump_zipped_text(next, zipped_length);
+}
+
+/**
* print_of_config_part
* @brief Print the name/value pairs of a partition
*
@@ -1476,6 +1598,8 @@ main (int argc, char *argv[])
int print_event_scan = 0;
int print_config_var = 0;
char *dump_name = NULL;
+ char *ascii_name = NULL;
+ char *zip_name = NULL;
char *update_config_var = NULL;
char *config_pname = "common";
@@ -1504,6 +1628,12 @@ main (int argc, char *argv[])
case 'd': /* dump */
dump_name = optarg;
break;
+ case 'a': /* ASCII dump */
+ ascii_name = optarg;
+ break;
+ case 'z': /* dump compressed data */
+ zip_name = optarg;
+ break;
case 'n': /* nvram-file */
nvram.filename = optarg;
break;
@@ -1641,6 +1771,12 @@ main (int argc, char *argv[])
if (dump_name)
if (dump_raw_partition(&nvram, dump_name) != 0)
ret = -1;
+ if (ascii_name)
+ if (dump_ascii_partition(&nvram, ascii_name) != 0)
+ ret = -1;
+ if (zip_name)
+ if (unzip_partition(&nvram, zip_name) != 0)
+ ret = -1;
err_exit:
if (nvram.data)
^ permalink raw reply related
* Re: [PATCH 2/2] ucc_geth: Fix deadlock
From: Joakim Tjernlund @ 2010-11-14 14:43 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: netdev, linuxppc-dev
In-Reply-To: <20101112140947.GB28223@oksana.dev.rtsoft.ru>
Anton Vorontsov <cbouatmailru@gmail.com> wrote on 2010/11/12 15:09:47:
>
> On Fri, Nov 12, 2010 at 02:55:09PM +0100, Joakim Tjernlund wrote:
> > This script:
> > while [ 1==1 ] ; do ifconfig eth0 up; usleep 1950000 ;ifconfig eth0 down; dmesg -c ;done
> > causes in just a second or two:
> > INFO: task ifconfig:572 blocked for more than 120 seconds.
> [...]
> > The reason appears to be ucc_geth_stop meets adjust_link as the
> > PHY reports PHY changes. I belive adjust_link hangs somewhere,
> > holding the PHY lock, because ucc_geth_stop disabled the
> > controller HW.
> > Fix is to stop the PHY before disabling the controller.
> >
> > Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
>
> It's unclear where exactly adjust_link() hangs, but the patch
> looks as the right thing overall.
Yes, I too cannot find where it is hanging, just that it is hanging somewhere.
I am starting to think it is hanging somewhere else. Anyhow, the hang
goes away 100% when this patch is applied.
Jocke
^ permalink raw reply
* Re: [PATCH v2] fsldma: add support to 36-bit physical address
From: Kumar Gala @ 2010-11-15 15:16 UTC (permalink / raw)
To: Timur Tabi; +Cc: dan.j.williams, linuxppc-dev, linux-kernel
In-Reply-To: <AANLkTi=1nutREorMFY2VJyUYQD0SHfiSeskw-u22P+R-@mail.gmail.com>
On Nov 13, 2010, at 4:43 PM, Timur Tabi wrote:
> On Thu, Nov 11, 2010 at 5:56 AM, Kumar Gala =
<galak@kernel.crashing.org> wrote:
>=20
>> Is there any reason we shouldn't set DMA_BIT_MASK(64) since the DMA =
block programming model allows the address to be 64-bits?
>=20
> Can you explain that? The DMA registers only have room for 36 bits
> for the physical address.
The programming model (if you look at the free-space in the registers =
and data structures) supports a 64-bit address. I'm trying to avoid =
changing the driver in the future if we have >36-bit. However this is =
such a minor worry that I'll stop and just ack the patch as is.
- k=
^ permalink raw reply
* Re: [PATCH v2] fsldma: add support to 36-bit physical address
From: Timur Tabi @ 2010-11-15 16:13 UTC (permalink / raw)
To: Kumar Gala; +Cc: dan.j.williams, linuxppc-dev, linux-kernel
In-Reply-To: <3B38AD35-39A2-4A54-8109-65D6DE436227@kernel.crashing.org>
On Mon, Nov 15, 2010 at 9:16 AM, Kumar Gala <galak@kernel.crashing.org> wro=
te:
> The programming model (if you look at the free-space in the registers and=
data structures) supports a 64-bit address. =A0I'm trying to avoid changin=
g the driver in the future if we have >36-bit. =A0However this is such a mi=
nor worry that I'll stop and just ack the patch as is.
I must still be missing something. I'm looking at the description of
the SATR register in the MPC8572 RM, and it shows this:
0 - 3 | 4 - 5 | 6 | 7 | 8 - 11 | 12 - 15 | 16-21 | 22-=
31
--- | STFLOWLVL | SPCIORDER | SSME | STRANSINT | SREADTTYPE | --- | ES=
AD
The most that we can extend ESAD to is 16 bits, for a total of a
48-bit physical address. Where are the other 16 bits supposed to go?
--=20
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* [PATCH 1/2] misc: at24: parse OF-data, too
From: Wolfram Sang @ 2010-11-15 17:25 UTC (permalink / raw)
To: devicetree-discuss; +Cc: linuxppc-dev
Information about the pagesize and read-only-status may also come from
the devicetree. Parse this data, too, and act accordingly. While we are
here, change the initialization printout a bit. write_max is useful to
know to detect performance bottlenecks, the rest is superfluous.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
Grant: As mentioned at ELCE10, I could pretty much respin this old approach I
tried roughly a year ago (just with archdata then). If the approach and docs
are good, I am fine with the patches entering via one of your trees.
Documentation/powerpc/dts-bindings/eeprom.txt | 28 ++++++++++++++++++++++
drivers/misc/eeprom/at24.c | 33 ++++++++++++++++++++-----
2 files changed, 53 insertions(+), 6 deletions(-)
create mode 100644 Documentation/powerpc/dts-bindings/eeprom.txt
diff --git a/Documentation/powerpc/dts-bindings/eeprom.txt b/Documentation/powerpc/dts-bindings/eeprom.txt
new file mode 100644
index 0000000..4342c10
--- /dev/null
+++ b/Documentation/powerpc/dts-bindings/eeprom.txt
@@ -0,0 +1,28 @@
+EEPROMs (I2C)
+
+Required properties:
+
+ - compatible : should be "<manufacturer>,<type>"
+ If there is no specific driver for <manufacturer>, a generic
+ driver based on <type> is selected. Possible types are:
+ 24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
+ 24c128, 24c256, 24c512, 24c1024, spd
+
+ - reg : the I2C address of the EEPROM
+
+Optional properties:
+
+ - pagesize : the length of the pagesize for writing. Please consult the
+ manual of your device, that value varies a lot. A wrong value
+ may result in data loss! If not specified, a safety value of
+ '1' is used which will be very slow.
+
+ - read-only: this parameterless property disables writes to the eeprom
+
+Example:
+
+eeprom@52 {
+ compatible = "atmel,24c32";
+ reg = <0x52>;
+ pagesize = <32>;
+};
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 559b0b3..aaf16cb 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -20,6 +20,7 @@
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
@@ -457,6 +458,27 @@ static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{
+ const u32 *val;
+ struct device_node *node = client->dev.of_node;
+
+ if (node) {
+ if (of_get_property(node, "read-only", NULL))
+ chip->flags |= AT24_FLAG_READONLY;
+ val = of_get_property(node, "pagesize", NULL);
+ if (val)
+ chip->page_size = *val;
+ }
+}
+#else
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{ }
+#endif /* CONFIG_OF */
+
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct at24_platform_data chip;
@@ -485,6 +507,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
chip.page_size = 1;
+ /* update chipdata if OF is present */
+ at24_get_ofdata(client, &chip);
+
chip.setup = NULL;
chip.context = NULL;
}
@@ -597,19 +622,15 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, at24);
- dev_info(&client->dev, "%zu byte %s EEPROM %s\n",
+ dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
at24->bin.size, client->name,
- writable ? "(writable)" : "(read-only)");
+ writable ? "writable" : "read-only", at24->write_max);
if (use_smbus == I2C_SMBUS_WORD_DATA ||
use_smbus == I2C_SMBUS_BYTE_DATA) {
dev_notice(&client->dev, "Falling back to %s reads, "
"performance will suffer\n", use_smbus ==
I2C_SMBUS_WORD_DATA ? "word" : "byte");
}
- dev_dbg(&client->dev,
- "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n",
- chip.page_size, num_addresses,
- at24->write_max, use_smbus);
/* export data to kernel code */
if (chip.setup)
--
1.7.2.3
^ permalink raw reply related
* [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Wolfram Sang @ 2010-11-15 17:25 UTC (permalink / raw)
To: devicetree-discuss; +Cc: linuxppc-dev
In-Reply-To: <1289841916-3825-1-git-send-email-w.sang@pengutronix.de>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
arch/powerpc/boot/dts/pcm030.dts | 1 +
arch/powerpc/boot/dts/pcm032.dts | 3 ++-
2 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
index 8a4ec30..e7c36bc 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -259,6 +259,7 @@
eeprom@52 {
compatible = "catalyst,24c32";
reg = <0x52>;
+ pagesize = <32>;
};
};
diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm032.dts
index 85d857a..e175e2c 100644
--- a/arch/powerpc/boot/dts/pcm032.dts
+++ b/arch/powerpc/boot/dts/pcm032.dts
@@ -257,8 +257,9 @@
reg = <0x51>;
};
eeprom@52 {
- compatible = "at24,24c32";
+ compatible = "catalyst,24c32";
reg = <0x52>;
+ pagesize = <32>;
};
};
--
1.7.2.3
^ permalink raw reply related
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Anton Vorontsov @ 2010-11-15 17:32 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <1289841916-3825-2-git-send-email-w.sang@pengutronix.de>
On Mon, Nov 15, 2010 at 06:25:16PM +0100, Wolfram Sang wrote:
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> ---
> arch/powerpc/boot/dts/pcm030.dts | 1 +
> arch/powerpc/boot/dts/pcm032.dts | 3 ++-
> 2 files changed, 3 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
> index 8a4ec30..e7c36bc 100644
> --- a/arch/powerpc/boot/dts/pcm030.dts
> +++ b/arch/powerpc/boot/dts/pcm030.dts
> @@ -259,6 +259,7 @@
> eeprom@52 {
> compatible = "catalyst,24c32";
> reg = <0x52>;
> + pagesize = <32>;
I think you'd better drop the pagesize property altogether, and
instead make the compatible string more specific (if needed at
all. are there any 'catalyst,24c32' chips with pagesize != 32?)
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH v2] fsldma: add support to 36-bit physical address
From: Kumar Gala @ 2010-11-15 15:17 UTC (permalink / raw)
To: Li Yang; +Cc: dan.j.williams, linuxppc-dev, linux-kernel
In-Reply-To: <1289477789-10651-1-git-send-email-leoli@freescale.com>
On Nov 11, 2010, at 6:16 AM, Li Yang wrote:
> Expand the dma_mask of fsldma device to 36-bit, indicating that the
> DMA engine can deal with 36-bit physical address and does not need
> the SWIOTLB to create bounce buffer for it when doing dma_map_*().
>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Add more detailed commit message
>
> drivers/dma/fsldma.c | 4 +++-
> 1 files changed, 3 insertions(+), 1 deletions(-)
Acked-by: Kumar Gala <galak@kernel.crashing.org>
- k
^ permalink raw reply
* Re: [PATCH v2] fsldma: add support to 36-bit physical address
From: Kumar Gala @ 2010-11-15 17:43 UTC (permalink / raw)
To: Timur Tabi; +Cc: dan.j.williams, linuxppc-dev, linux-kernel
In-Reply-To: <AANLkTin8+13mr-tV-2iCG+zGRfF6xZ23cN+=44dsaQor@mail.gmail.com>
On Nov 15, 2010, at 10:13 AM, Timur Tabi wrote:
> On Mon, Nov 15, 2010 at 9:16 AM, Kumar Gala =
<galak@kernel.crashing.org> wrote:
>=20
>> The programming model (if you look at the free-space in the registers =
and data structures) supports a 64-bit address. I'm trying to avoid =
changing the driver in the future if we have >36-bit. However this is =
such a minor worry that I'll stop and just ack the patch as is.
>=20
> I must still be missing something. I'm looking at the description of
> the SATR register in the MPC8572 RM, and it shows this:
>=20
> 0 - 3 | 4 - 5 | 6 | 7 | 8 - 11 | 12 - 15 | 16-21 =
| 22-31
> --- | STFLOWLVL | SPCIORDER | SSME | STRANSINT | SREADTTYPE | --- | =
ESAD
>=20
> The most that we can extend ESAD to is 16 bits, for a total of a
> 48-bit physical address. Where are the other 16 bits supposed to go?
I was looking at the link addresses. I stand corrected so our max is =
48-bits.
- k=
^ permalink raw reply
* Re: [PATCH v2] fsldma: add support to 36-bit physical address
From: Scott Wood @ 2010-11-15 17:53 UTC (permalink / raw)
To: Kumar Gala; +Cc: Timur Tabi, linuxppc-dev, dan.j.williams, linux-kernel
In-Reply-To: <72D46FED-AFC8-4599-ADB0-2A2B634CCE48@kernel.crashing.org>
On Mon, 15 Nov 2010 11:43:12 -0600
Kumar Gala <galak@kernel.crashing.org> wrote:
>
> On Nov 15, 2010, at 10:13 AM, Timur Tabi wrote:
>
> > On Mon, Nov 15, 2010 at 9:16 AM, Kumar Gala <galak@kernel.crashing.org> wrote:
> >
> >> The programming model (if you look at the free-space in the registers and data structures) supports a 64-bit address. I'm trying to avoid changing the driver in the future if we have >36-bit. However this is such a minor worry that I'll stop and just ack the patch as is.
> >
> > I must still be missing something. I'm looking at the description of
> > the SATR register in the MPC8572 RM, and it shows this:
> >
> > 0 - 3 | 4 - 5 | 6 | 7 | 8 - 11 | 12 - 15 | 16-21 | 22-31
> > --- | STFLOWLVL | SPCIORDER | SSME | STRANSINT | SREADTTYPE | --- | ESAD
> >
> > The most that we can extend ESAD to is 16 bits, for a total of a
> > 48-bit physical address. Where are the other 16 bits supposed to go?
>
> I was looking at the link addresses. I stand corrected so our max is 48-bits.
Looks like 42 bits -- just because bits 16-21 could be used to extend
ESAD doesn't mean that they have been.
-Scott
^ permalink raw reply
* [PATCH v2] PPC4xx: Adding PCI(E) MSI support
From: tmarri @ 2010-11-15 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: tmarri
From: Tirumala Marri <tmarri@apm.com>
This patch adds MSI support for 440SPe, 460Ex, 460Sx and 405Ex.
Signed-off-by: Tirumala R Marri <tmarri@apm.com>
---
v1:
* Get rid of bitmap functions.
* Remove irq mapping as each MSI is tied to UIC.
* Cleaning up of prints.
v2:
* Remove or add blank lines at appropriate places.
* Added BITMAP as it is easy to request and free the MSIs
* Removed UPPER_4BITS_OF36BIT & LOWER_32BITS_OF36BIT;
* Remove unused feature variable.
* Remove initialization of "virq".
* remove static int_no varaible and replace with bitmap.
* Eliminated reading count from DTS tree and added a macro.
* Remove printK.
* Remove else in setup_irqs.
* Free interrupts in teardown_msi_interrupts().
* Print contraints in check_device().
* Replace ioremap with of_iomap().
* Use msi_data in setup_pcieh_hw().
* Don't unmap in the setup_pcieh_hw().
* don't use WARN_ON.
* Remove ppc4xx_msi_ids[].
---
arch/powerpc/boot/dts/canyonlands.dts | 18 ++
arch/powerpc/boot/dts/katmai.dts | 18 ++
arch/powerpc/boot/dts/kilauea.dts | 28 +++
arch/powerpc/boot/dts/redwood.dts | 20 ++
arch/powerpc/platforms/40x/Kconfig | 2 +
arch/powerpc/platforms/44x/Kconfig | 6 +
arch/powerpc/sysdev/Kconfig | 7 +
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/ppc4xx_msi.c | 311 +++++++++++++++++++++++++++++++++
9 files changed, 411 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index a303703..5a8e04e 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -519,5 +519,23 @@
0x0 0x0 0x0 0x3 &UIC3 0x12 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0x13 0x4 /* swizzled int D */>;
};
+
+ MSI: ppc4xx-msi@C10000000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0xC 0x10000000 0x100>;
+ sdr-base = <0x36C>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts = <0 1 2 3>;
+ interrupt-parent = <&UIC3>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC3 0x18 1
+ 1 &UIC3 0x19 1
+ 2 &UIC3 0x1A 1
+ 3 &UIC3 0x1B 1>;
+ };
};
};
diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts
index 7c3be5e..f913dbe 100644
--- a/arch/powerpc/boot/dts/katmai.dts
+++ b/arch/powerpc/boot/dts/katmai.dts
@@ -442,6 +442,24 @@
0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
};
+ MSI: ppc4xx-msi@400300000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0x4 0x00300000 0x100>;
+ sdr-base = <0x3B0>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts =<0 1 2 3>;
+ interrupt-parent = <&UIC0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC0 0xC 1
+ 1 &UIC0 0x0D 1
+ 2 &UIC0 0x0E 1
+ 3 &UIC0 0x0F 1>;
+ };
+
I2O: i2o@400100000 {
compatible = "ibm,i2o-440spe";
reg = <0x00000004 0x00100000 0x100>;
diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts
index 083e68e..21e88f5 100644
--- a/arch/powerpc/boot/dts/kilauea.dts
+++ b/arch/powerpc/boot/dts/kilauea.dts
@@ -394,5 +394,33 @@
0x0 0x0 0x0 0x3 &UIC2 0xd 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC2 0xe 0x4 /* swizzled int D */>;
};
+
+ MSI: ppc4xx-msi@C10000000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0x0 0xEF620000 0x100>;
+ sdr-base = <0x4B0>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <12>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 0xA 0xB 0xC 0xD>;
+ interrupt-parent = <&UIC2>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC2 0x10 1
+ 1 &UIC2 0x11 1
+ 2 &UIC2 0x12 1
+ 2 &UIC2 0x13 1
+ 2 &UIC2 0x14 1
+ 2 &UIC2 0x15 1
+ 2 &UIC2 0x16 1
+ 2 &UIC2 0x17 1
+ 2 &UIC2 0x18 1
+ 2 &UIC2 0x19 1
+ 2 &UIC2 0x1A 1
+ 2 &UIC2 0x1B 1
+ 2 &UIC2 0x1C 1
+ 3 &UIC2 0x1D 1>;
+ };
};
};
diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
index 81636c0..d86a3a4 100644
--- a/arch/powerpc/boot/dts/redwood.dts
+++ b/arch/powerpc/boot/dts/redwood.dts
@@ -358,8 +358,28 @@
0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
};
+ MSI: ppc4xx-msi@400300000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0x4 0x00300000 0x100
+ 0x4 0x00300000 0x100>;
+ sdr-base = <0x3B0>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts =<0 1 2 3>;
+ interrupt-parent = <&UIC0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC0 0xC 1
+ 1 &UIC0 0x0D 1
+ 2 &UIC0 0x0E 1
+ 3 &UIC0 0x0F 1>;
+ };
+
};
+
chosen {
linux,stdout-path = "/plb/opb/serial@ef600200";
};
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig
index b721764..92aeee6 100644
--- a/arch/powerpc/platforms/40x/Kconfig
+++ b/arch/powerpc/platforms/40x/Kconfig
@@ -57,6 +57,8 @@ config KILAUEA
select 405EX
select PPC40x_SIMPLE
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select 4xx_MSI
help
This option enables support for the AMCC PPC405EX evaluation board.
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 0f979c5..3836353 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -74,6 +74,8 @@ config KATMAI
select 440SPe
select PCI
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select 4xx_MSI
help
This option enables support for the AMCC PPC440SPe evaluation board.
@@ -119,6 +121,8 @@ config CANYONLANDS
select 460EX
select PCI
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select 4xx_MSI
select IBM_NEW_EMAC_RGMII
select IBM_NEW_EMAC_ZMII
help
@@ -145,6 +149,8 @@ config REDWOOD
select 460SX
select PCI
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select 4xx_MSI
help
This option enables support for the AMCC PPC460SX Redwood board.
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 3965828..32f5a40 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
depends on PCI && 4xx
default n
+config 4xx_MSI
+ bool
+ depends on PCI_MSI
+ depends on PCI && 4xx
+ default n
+
config PPC_MSI_BITMAP
bool
depends on PCI_MSI
default y if MPIC
default y if FSL_PCI
+ default y if 4xx_MSI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 0bef9da..df859a6 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o
ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_4xx) += ppc4xx_pci.o
endif
+obj-$(CONFIG_4xx_MSI) += ppc4xx_msi.o
obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o
obj-$(CONFIG_CPM) += cpm_common.o
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
new file mode 100644
index 0000000..9ed559f
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -0,0 +1,311 @@
+/*
+ * Adding PCI-E MSI support for PPC4XX SoCs.
+ *
+ * Copyright (c) 2010, Applied Micro Circuits Corporation
+ * Authors: Tirumala R Marri <tmarri@apm.com>
+ * Feng Kan <fkan@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <boot/dcr.h>
+#include <asm/dcr-regs.h>
+#include <asm/msi_bitmap.h>
+
+#define PEIH_TERMADH 0x00
+#define PEIH_TERMADL 0x08
+#define PEIH_MSIED 0x10
+#define PEIH_MSIMK 0x18
+#define PEIH_MSIASS 0x20
+#define PEIH_FLUSH0 0x30
+#define PEIH_FLUSH1 0x38
+#define PEIH_CNTRST 0x48
+#define NR_MSI_IRQS 4
+
+LIST_HEAD(msi_head);
+struct ppc4xx_msi {
+ u32 msi_addr_lo;
+ u32 msi_addr_hi;
+ void __iomem *msi_regs;
+ int msi_virqs[NR_MSI_IRQS];
+ struct msi_bitmap bitmap;
+ struct list_head list;
+};
+
+struct ppc4xx_msi_feature {
+ u32 ppc4xx_pic_ip;
+ u32 msiir_offset;
+};
+
+static int ppc4xx_msi_init_allocator(struct platform_device *dev,
+ struct ppc4xx_msi *msi_data)
+{
+ int err;
+
+ err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+ dev->dev.of_node);
+ if (err)
+ return err;
+
+ err = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+ if (err < 0) {
+ msi_bitmap_free(&msi_data->bitmap);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ int err = 0;
+ int int_no = -ENOMEM;
+ unsigned int virq;
+ struct msi_msg msg;
+ struct msi_desc *entry;
+ struct device_node *msi_dev = NULL;
+ struct ppc4xx_msi *msi_data = dev->dev.platform_data;
+
+ msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
+ if (msi_dev) {
+ err = -ENODEV;
+ goto out_free;
+ }
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ list_for_each_entry(msi_data, &msi_head, list) {
+ int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ if(int_no >= 0)
+ break;
+ }
+ if(int_no < 0) {
+
+ err = int_no;
+ pr_debug("%s: fail allocating msi interrupt\n",
+ __func__);
+ }
+ virq = irq_of_parse_and_map(msi_dev, int_no);
+ if (virq == NO_IRQ) {
+ dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1);
+ err = -ENOSPC;
+ goto out_free;
+ }
+ msi_data->msi_virqs[int_no] = virq;
+ set_irq_data(virq, (void *)int_no);
+ dev_dbg(&dev->dev, "%s: virq = %d \n", __func__, virq);
+
+ /* Setup msi address space */
+ msg.address_hi = msi_data->msi_addr_hi;
+ msg.address_lo = msi_data->msi_addr_lo;
+
+ set_irq_msi(virq, entry);
+ msg.data = int_no;
+ write_msi_msg(virq, &msg);
+ }
+ of_node_put(msi_dev);
+ return err;
+
+out_free:
+ of_node_put(msi_dev);
+ return err;
+}
+
+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+ struct ppc4xx_msi *msi_data = dev->dev.platform_data;
+
+ dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq == NO_IRQ)
+ continue;
+ set_irq_msi(entry->irq, NULL);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap,
+ virq_to_hw(entry->irq), 1);
+ irq_dispose_mapping(entry->irq);
+ }
+
+ return;
+}
+
+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+ dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n",
+ __func__, nvec, type);
+ if (type == PCI_CAP_ID_MSIX)
+ pr_debug("fslmsi: MSI-X untested, trying anyway.\n");
+
+ return 0;
+}
+
+static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
+ struct resource res, struct ppc4xx_msi *msi)
+{
+ const u32 *msi_data;
+ const u32 *msi_mask;
+ const u32 *sdr_addr;
+ int err = 0;
+ dma_addr_t msi_phys;
+ void *msi_virt;
+ struct device_node *msi_dev = NULL;
+
+ sdr_addr = of_get_property(dev->dev.of_node, "sdr-base", NULL);
+ if (!sdr_addr)
+ return -1;
+
+ SDR0_WRITE(sdr_addr, (u64)res.start >> 32); /*HIGH addr */
+ SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
+
+
+ msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
+ if (msi_dev) {
+ err = -ENODEV;
+ goto error_out;
+ }
+ msi->msi_regs = of_iomap(msi_dev, 0);
+ if (!msi->msi_regs) {
+ dev_err(&dev->dev, "ioremap problem failed\n");
+ return -ENOMEM;
+ }
+ of_node_put(msi_dev);
+ dev_dbg(&dev->dev, "PCIE-MSI: msi register mapped 0x%x 0x%x\n",
+ (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs));
+
+ msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
+ msi->msi_addr_hi = 0x0;
+ msi->msi_addr_lo = (u32) msi_phys;
+ dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x \n", msi->msi_addr_lo);
+
+ /* Progam the Interrupt handler Termination addr registers */
+ out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
+ out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
+
+ msi_data = of_get_property(dev->dev.of_node, "msi-data", NULL);
+ if (!msi_data) {
+ err = -1;
+ goto error_out;
+ }
+
+ msi_mask = of_get_property(dev->dev.of_node, "msi-mask", NULL);
+ if (!msi_mask) {
+ err = -1;
+ goto error_out;
+ }
+
+ /* Program MSI Expected data and Mask bits */
+ out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
+ out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
+
+ return err;
+error_out:
+ return err;
+}
+
+static int ppc4xx_of_msi_remove(struct platform_device *dev)
+{
+ struct ppc4xx_msi *msi = dev->dev.platform_data;
+ int i;
+ int virq;
+
+ for(i = 0; i < NR_MSI_IRQS; i++) {
+ virq = msi->msi_virqs[i];
+ if (virq != NO_IRQ)
+ irq_dispose_mapping(virq);
+ }
+
+ if (msi->list.prev != NULL)
+ list_del(&msi->list);
+
+ if (msi->bitmap.bitmap)
+ msi_bitmap_free(&msi->bitmap);
+ iounmap(msi->msi_regs);
+ kfree(msi);
+
+ return 0;
+}
+
+static int __devinit ppc4xx_msi_probe(struct platform_device *dev,
+ const struct of_device_id *match)
+{
+ struct ppc4xx_msi *msi;
+ struct resource res;
+ int err = 0;
+
+ dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
+
+ msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
+ if (!msi) {
+ dev_err(&dev->dev, "No memory for MSI structure\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+ dev->dev.platform_data = msi;
+
+ /* Get MSI ranges */
+ err = of_address_to_resource(dev->dev.of_node, 0, &res);
+ if (err) {
+ dev_err(&dev->dev, "%s resource error!\n",
+ dev->dev.of_node->full_name);
+ goto error_out;
+ }
+
+ if (ppc4xx_setup_pcieh_hw(dev, res, msi))
+ goto error_out;
+
+ err = ppc4xx_msi_init_allocator(dev, msi);
+ if (err) {
+ dev_err(&dev->dev, "Error allocating MSI bitmap\n");
+ goto error_out;
+ }
+
+ list_add_tail(&msi->list, &msi_head);
+
+ ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+ ppc_md.msi_check_device = ppc4xx_msi_check_device;
+ return err;
+
+error_out:
+ ppc4xx_of_msi_remove(dev);
+ return err;
+}
+
+static struct of_platform_driver ppc4xx_msi_driver = {
+ .driver = {
+ .name = "ppc4xx-msi",
+ .owner = THIS_MODULE,
+ },
+ .probe = ppc4xx_msi_probe,
+ .remove = ppc4xx_of_msi_remove,
+};
+
+static __init int ppc4xx_msi_init(void)
+{
+ return of_register_platform_driver(&ppc4xx_msi_driver);
+}
+
+subsys_initcall(ppc4xx_msi_init);
--
1.6.1.rc3
^ permalink raw reply related
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Mitch Bradley @ 2010-11-15 21:06 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <20101115173250.GA22104@oksana.dev.rtsoft.ru>
On 11/15/2010 7:32 AM, Anton Vorontsov wrote:
> On Mon, Nov 15, 2010 at 06:25:16PM +0100, Wolfram Sang wrote:
>> Signed-off-by: Wolfram Sang<w.sang@pengutronix.de>
>> ---
>> arch/powerpc/boot/dts/pcm030.dts | 1 +
>> arch/powerpc/boot/dts/pcm032.dts | 3 ++-
>> 2 files changed, 3 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
>> index 8a4ec30..e7c36bc 100644
>> --- a/arch/powerpc/boot/dts/pcm030.dts
>> +++ b/arch/powerpc/boot/dts/pcm030.dts
>> @@ -259,6 +259,7 @@
>> eeprom@52 {
>> compatible = "catalyst,24c32";
>> reg =<0x52>;
>> + pagesize =<32>;
>
> I think you'd better drop the pagesize property altogether, and
> instead make the compatible string more specific (if needed at
> all. are there any 'catalyst,24c32' chips with pagesize != 32?)
Microchip makes a 24c32 part that looks pretty similar to the catalyst
part, but Microchip's has a 64-byte page size compared to Catalyst's 32.
It would probably be feasible to have a generic I2C EEPROM driver that
could handle many different parts, parameterized by total size, block
size, and page size.
>
> Thanks,
>
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Anton Vorontsov @ 2010-11-15 21:24 UTC (permalink / raw)
To: Mitch Bradley; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <4CE1A0E4.5030505@firmworks.com>
On Mon, Nov 15, 2010 at 11:06:44AM -1000, Mitch Bradley wrote:
[...]
> >> eeprom@52 {
> >> compatible = "catalyst,24c32";
> >> reg =<0x52>;
> >>+ pagesize =<32>;
> >
> >I think you'd better drop the pagesize property altogether, and
> >instead make the compatible string more specific (if needed at
> >all. are there any 'catalyst,24c32' chips with pagesize != 32?)
>
> Microchip makes a 24c32 part that looks pretty similar to the
> catalyst part, but Microchip's has a 64-byte page size compared to
> Catalyst's 32.
Well, when using microchip part, the compatible string would be
"microchip,24c32", correct? Then we have all the information
already, no need for the pagesize.
> It would probably be feasible to have a generic I2C EEPROM driver
> that could handle many different parts, parameterized by total size,
> block size, and page size.
I guess it can do this already via I2C ID table. The problem
is that I2C core is only using part ID (no vendor ID matching).
So, the current driver may just implement quirks like this:
if (of_device_is_compatible(np, "catalyst,24c32"))
pagesize = 32;
Or, if it's some generic pattern, something like
if (of_device_is_compatible_vendor(np, "catalyst"))
pagesize /= 2;
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 1/2] misc: at24: parse OF-data, too
From: Grant Likely @ 2010-11-15 21:41 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <1289841916-3825-1-git-send-email-w.sang@pengutronix.de>
On Mon, Nov 15, 2010 at 10:25 AM, Wolfram Sang <w.sang@pengutronix.de> wrot=
e:
> Information about the pagesize and read-only-status may also come from
> the devicetree. Parse this data, too, and act accordingly. While we are
> here, change the initialization printout a bit. write_max is useful to
> know to detect performance bottlenecks, the rest is superfluous.
>
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> ---
>
> Grant: As mentioned at ELCE10, I could pretty much respin this old approa=
ch I
> tried roughly a year ago (just with archdata then). If the approach and d=
ocs
> are good, I am fine with the patches entering via one of your trees.
>
> =A0Documentation/powerpc/dts-bindings/eeprom.txt | =A0 28 +++++++++++++++=
+++++++
> =A0drivers/misc/eeprom/at24.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =
=A0 33 ++++++++++++++++++++-----
> =A02 files changed, 53 insertions(+), 6 deletions(-)
> =A0create mode 100644 Documentation/powerpc/dts-bindings/eeprom.txt
>
> diff --git a/Documentation/powerpc/dts-bindings/eeprom.txt b/Documentatio=
n/powerpc/dts-bindings/eeprom.txt
> new file mode 100644
> index 0000000..4342c10
> --- /dev/null
> +++ b/Documentation/powerpc/dts-bindings/eeprom.txt
> @@ -0,0 +1,28 @@
> +EEPROMs (I2C)
> +
> +Required properties:
> +
> + =A0- compatible : should be "<manufacturer>,<type>"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0If there is no specific driver for <manu=
facturer>, a generic
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0driver based on <type> is selected. Poss=
ible types are:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A024c00, 24c01, 24c02, 24c04, 24c08, 24c16=
, 24c32, 24c64,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A024c128, 24c256, 24c512, 24c1024, spd
> +
> + =A0- reg : the I2C address of the EEPROM
> +
> +Optional properties:
> +
> + =A0- pagesize : the length of the pagesize for writing. Please consult =
the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 manual of your device, that value varies a =
lot. A wrong value
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0may result in data loss! If not specified, a=
safety value of
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0'1' is used which will be very slow.
As Anton mentions, the compatible value should be specific enough that
a pagesize property isn't needed (assuming there aren't at24 devices
with differing page sizes), but that leaves the question of where to
put the page size data in the driver. I think the obvious answer is
to put it in the at24_ids table. This would also be a good thing for
the non-OF use-cases too. Unfortunately the driver_data field is
already in use and requires refactoring to turn driver_data into a
pointer to a structure, and so requires more work (sorry).
A refactored at24_ids table might look something like (there may be a
cleaner way to go about it though, I used the macro to solve the
problem of constructing an at24_platform_data structure for each entry
and storing a pointer to it in the unsigned long driver_data field):
#define AT24_DEVDATA(_len, _page_size, _flags) \
((unsigned long)((struct at24_platform_data[]) \
{{.byte_len =3D len, .page_size =3D _page_size, .flags =3D
_flags}}))
static const struct i2c_device_id at24_ids[] =3D {
/* needs 8 addresses as A0-A2 are ignored */
{ "24c00", AT24_DEVDATA(128 / 8, 16, AT24_FLAG_TAKE8ADDR) },
/* old variants can't be handled with this generic entry! */
{ "24c01", AT24_DEVDATA(1024 / 8, 16, 0) },
{ "24c02", AT24_DEVDATA(2048 / 8, 16, 0) },
...
};
This will also make the probe code simpler.
However, if I am wrong and similarly named at24 devices have different
page sizes, then encoding it in a property is the right thing to do.
Also, the read-only property is fine.
g.
> +
> + =A0- read-only: this parameterless property disables writes to the eepr=
om
> +
> +Example:
> +
> +eeprom@52 {
> + =A0 =A0 =A0 compatible =3D "atmel,24c32";
> + =A0 =A0 =A0 reg =3D <0x52>;
> + =A0 =A0 =A0 pagesize =3D <32>;
> +};
> diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> index 559b0b3..aaf16cb 100644
> --- a/drivers/misc/eeprom/at24.c
> +++ b/drivers/misc/eeprom/at24.c
> @@ -20,6 +20,7 @@
> =A0#include <linux/log2.h>
> =A0#include <linux/bitops.h>
> =A0#include <linux/jiffies.h>
> +#include <linux/of.h>
> =A0#include <linux/i2c.h>
> =A0#include <linux/i2c/at24.h>
>
> @@ -457,6 +458,27 @@ static ssize_t at24_macc_write(struct memory_accesso=
r *macc, const char *buf,
>
> =A0/*--------------------------------------------------------------------=
-----*/
>
> +#ifdef CONFIG_OF
> +static void at24_get_ofdata(struct i2c_client *client,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct at24_platform_data *chip)
> +{
> + =A0 =A0 =A0 const u32 *val;
> + =A0 =A0 =A0 struct device_node *node =3D client->dev.of_node;
> +
> + =A0 =A0 =A0 if (node) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (of_get_property(node, "read-only", NULL=
))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 chip->flags |=3D AT24_FLAG_=
READONLY;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D of_get_property(node, "pagesize", N=
ULL);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (val)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 chip->page_size =3D *val;
> + =A0 =A0 =A0 }
> +}
> +#else
> +static void at24_get_ofdata(struct i2c_client *client,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct at24_platform_data *chip)
> +{ }
> +#endif /* CONFIG_OF */
> +
> =A0static int at24_probe(struct i2c_client *client, const struct i2c_devi=
ce_id *id)
> =A0{
> =A0 =A0 =A0 =A0struct at24_platform_data chip;
> @@ -485,6 +507,9 @@ static int at24_probe(struct i2c_client *client, cons=
t struct i2c_device_id *id)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 */
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0chip.page_size =3D 1;
>
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* update chipdata if OF is present */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 at24_get_ofdata(client, &chip);
> +
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0chip.setup =3D NULL;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0chip.context =3D NULL;
> =A0 =A0 =A0 =A0}
> @@ -597,19 +622,15 @@ static int at24_probe(struct i2c_client *client, co=
nst struct i2c_device_id *id)
>
> =A0 =A0 =A0 =A0i2c_set_clientdata(client, at24);
>
> - =A0 =A0 =A0 dev_info(&client->dev, "%zu byte %s EEPROM %s\n",
> + =A0 =A0 =A0 dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/wr=
ite\n",
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0at24->bin.size, client->name,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 writable ? "(writable)" : "(read-only)");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 writable ? "writable" : "read-only", at24->=
write_max);
> =A0 =A0 =A0 =A0if (use_smbus =3D=3D I2C_SMBUS_WORD_DATA ||
> =A0 =A0 =A0 =A0 =A0 =A0use_smbus =3D=3D I2C_SMBUS_BYTE_DATA) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_notice(&client->dev, "Falling back to =
%s reads, "
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "performance will suf=
fer\n", use_smbus =3D=3D
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 I2C_SMBUS_WORD_DATA ?=
"word" : "byte");
> =A0 =A0 =A0 =A0}
> - =A0 =A0 =A0 dev_dbg(&client->dev,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 "page_size %d, num_addresses %d, write_max =
%d, use_smbus %d\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 chip.page_size, num_addresses,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 at24->write_max, use_smbus);
>
> =A0 =A0 =A0 =A0/* export data to kernel code */
> =A0 =A0 =A0 =A0if (chip.setup)
> --
> 1.7.2.3
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Grant Likely @ 2010-11-15 21:58 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: Mitch Bradley, linuxppc-dev, devicetree-discuss
In-Reply-To: <20101115212432.GA17754@oksana.dev.rtsoft.ru>
On Mon, Nov 15, 2010 at 2:24 PM, Anton Vorontsov <cbouatmailru@gmail.com> w=
rote:
> On Mon, Nov 15, 2010 at 11:06:44AM -1000, Mitch Bradley wrote:
> [...]
>> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0eeprom@52 {
>> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D=
"catalyst,24c32";
>> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg =3D<0x52>;
>> >>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pagesize =3D<32>=
;
>> >
>> >I think you'd better drop the pagesize property altogether, and
>> >instead make the compatible string more specific (if needed at
>> >all. are there any 'catalyst,24c32' chips with pagesize !=3D 32?)
>>
>> Microchip makes a 24c32 part that looks pretty similar to the
>> catalyst part, but Microchip's has a 64-byte page size compared to
>> Catalyst's 32.
>
> Well, when using microchip part, the compatible string would be
> "microchip,24c32", correct? Then we have all the information
> already, no need for the pagesize.
>
>> It would probably be feasible to have a generic I2C EEPROM driver
>> that could handle many different parts, parameterized by total size,
>> block size, and page size.
The current at24.c driver is already parameterized; but part of the
parameter data is statically linked into the board support code.
>
> I guess it can do this already via I2C ID table. The problem
> is that I2C core is only using part ID (no vendor ID matching).
This could potentially be changed for at24 devices since the i2c
subsystem already matches by name. It would mean adding the vendor
prefix to all instantiations of the device in the kernel, although it
would mess up the current heuristic used by of_modalias_node() (not a
show-stopper).
>
> So, the current driver may just implement quirks like this:
>
> if (of_device_is_compatible(np, "catalyst,24c32"))
> =A0 =A0 =A0 =A0pagesize =3D 32;
>
> Or, if it's some generic pattern, something like
>
> if (of_device_is_compatible_vendor(np, "catalyst"))
> =A0 =A0 =A0 =A0pagesize /=3D 2;
This would get ugly in a hurry. It would be better to make it data
driven by searching for a better match in an of_device_id table so
that the workarounds don't grow over time and eventually achieve
sentience.
g.
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Mitch Bradley @ 2010-11-15 22:17 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <AANLkTi=H_zONah7YuKSffkGrSiGa+7-LSbXE+qO=86Zj@mail.gmail.com>
In general I think it's better to report parameter values directly,
instead of inferring them from manufacturer and part numbers. That way
you at least have a fighting chance of avoiding a kernel upgrade when a
part changes.
Of course, that only works when the device tree is exported from the
boot firmware instead of having to carry the device tree inside the kernel.
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: Wolfram Sang @ 2010-11-15 22:11 UTC (permalink / raw)
To: Anton Vorontsov; +Cc: Mitch Bradley, linuxppc-dev, devicetree-discuss
In-Reply-To: <20101115212432.GA17754@oksana.dev.rtsoft.ru>
[-- Attachment #1: Type: text/plain, Size: 1352 bytes --]
> > >I think you'd better drop the pagesize property altogether, and
> > >instead make the compatible string more specific (if needed at
> > >all. are there any 'catalyst,24c32' chips with pagesize != 32?)
> >
> > Microchip makes a 24c32 part that looks pretty similar to the
> > catalyst part, but Microchip's has a 64-byte page size compared to
> > Catalyst's 32.
>
> Well, when using microchip part, the compatible string would be
> "microchip,24c32", correct? Then we have all the information
> already, no need for the pagesize.
Hmm, there are myriads of I2C eeproms out there, this table would be enourmous.
Even worse, I seem to recall that I had once seen a manufacturer increasing the
page-size from one charge to the next without changing the part-number, so I
got this feeling "you can't map pagesize to manufacturer/type" which I still
have. Sadly, this was long ago, so I can't proof it right now. Will try to dig
up some datasheets when in the office tomorrow. In general, I2C EEPROMs are
really a mess, the basic access method is the same, but except that everything
else is possible :) Thus, this approach. Thus, this approach.
Regards,
Wolfram
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: pcm030/032: add pagesize to dts
From: David Gibson @ 2010-11-15 22:30 UTC (permalink / raw)
To: Mitch Bradley; +Cc: linuxppc-dev, devicetree-discuss
In-Reply-To: <4CE1B18F.2030906@firmworks.com>
On Mon, Nov 15, 2010 at 12:17:51PM -1000, Mitch Bradley wrote:
> In general I think it's better to report parameter values directly,
> instead of inferring them from manufacturer and part numbers. That
> way you at least have a fighting chance of avoiding a kernel upgrade
> when a part changes.
I tend to agree. Although a fallback to deducing from the
manufacturer / part id if the pagesize property is missing would be
sensible.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* RE: [PATCH][v3] fsl_rio: move machine_check handler into machine_check_e500 & machine_check_e500mc
From: Xie Shaohui-B21989 @ 2010-11-16 2:42 UTC (permalink / raw)
To: Bounine, Alexandre, Xie Shaohui-B21989, linuxppc-dev
Cc: akpm, Gala Kumar-B11780, Li Yang-R58472, Zang Roy-R61911
In-Reply-To: <0CE8B6BE3C4AD74AB97D9D29BD24E55201539084@CORPEXCH1.na.ads.idt.com>
> -----Original Message-----
> From: Bounine, Alexandre [mailto:Alexandre.Bounine@idt.com]
> Sent: Saturday, November 13, 2010 12:30 AM
> To: Xie Shaohui-B21989; linuxppc-dev@lists.ozlabs.org
> Cc: akpm@linux-foundation.org; Li Yang-R58472; Gala Kumar-B11780; Zang
> Roy-R61911
> Subject: RE: [PATCH][v3] fsl_rio: move machine_check handler into
> machine_check_e500 & machine_check_e500mc
>=20
> > int machine_check_e500mc(struct pt_regs *regs) int
> > machine_check_e500(struct pt_regs *regs) {
> > unsigned long reason =3D get_mc_reason(regs);
> > + int ret =3D 0;
> > +
> > + if (reason & MCSR_BUS_RBERR) {
> > + ret =3D fsl_rio_mcheck_exception(regs);
> > + if (ret =3D=3D 1)
> > + return ret;
> > + }
>=20
> Do we really need 'ret' variable here?
> There is no further use of it by the rest of the code.
> Maybe just return 1 here if fsl_rio_mcheck_exception() returns 1 ?
>=20
> >
Ok, I'll remove the ret, do you have any comment for the error handler
patch?
http://patchwork.ozlabs.org/patch/69962/
Thanks & Best Regards,
Shaohui
^ permalink raw reply
* Re: Can't boot benh/powerpc.git kernel
From: Michael Neuling @ 2010-11-16 3:26 UTC (permalink / raw)
To: Jim Keniston; +Cc: linuxppc-dev
In-Reply-To: <1289520464.4752.12.camel@localhost>
In message <1289520464.4752.12.camel@localhost> you wrote:
> On Thu, 2010-11-11 at 09:06 +1100, Benjamin Herrenschmidt wrote:
> > On Wed, 2010-11-10 at 11:54 -0800, Jim Keniston wrote:
> > > I got Ben's linux/kernel/git/benh/powerpc.git source and built it
> > > (.config file attached*). It hangs on boot. When I boot it with
> > > loglevel=8, its last words are:
> >
> > First, please try with Linus upstream. The "master" branch in my git
> > tree is quite stale, and my next and merge branch are too at the moment
> > as I'm still travelling. All our current stuff was merged during the
> > last merge window so there's nothing "new" for you to pickup in my tree
> > at the moment :-)
> >
> > If the problem still occurs, I'll have a look next week.
> >
> > Cheers,
> > Ben.
>
> I built from Linus's git tree, and that kernel doesn't boot, either.
> (It doesn't hang, but rather panics during boot. I can provide a
> console log if you like.)
Yes please.
Linus' tree with pseries_defconfig boots fine for me on my POWER5 box.
> v2.6.36 and v2.6.37-rc1 boot fine for me. I'll post my nvram-related
> patches against v2.6.37-rc1.
So it's broken between 37-rc1 and whereever you grabbed Linus tree.
That's a fairly small window. Can you bisect it?
Mikey
^ permalink raw reply
* Re: [PATCH] Move ams driver to macintosh
From: Benjamin Herrenschmidt @ 2010-11-16 4:33 UTC (permalink / raw)
To: Jean Delvare
Cc: Michael Hanselmann, LM Sensors, Stelian Pop, linuxppc-dev,
Guenter Roeck
In-Reply-To: <20101005121043.08771994@endymion.delvare>
On Tue, 2010-10-05 at 12:10 +0200, Jean Delvare wrote:
> The ams driver isn't a hardware monitoring driver, so it shouldn't
> live under driver/hwmon. drivers/macintosh seems much more
> appropriate, as the driver is only useful on PowerBooks and iBooks.
Going through backlog... Do you want me to carry this in powerpc or
you'll deal with it directly ?
> Signed-off-by: Jean Delvare <khali@linux-fr.org>
> Cc: Guenter Roeck <guenter.roeck@ericsson.com>
> Cc: Stelian Pop <stelian@popies.net>
> Cc: Michael Hanselmann <linux-kernel@hansmi.ch>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> ---
> MAINTAINERS | 2
> drivers/hwmon/Kconfig | 26 ---
> drivers/hwmon/Makefile | 1
> drivers/hwmon/ams/Makefile | 8 -
> drivers/hwmon/ams/ams-core.c | 250 ---------------------------------
> drivers/hwmon/ams/ams-i2c.c | 277 -------------------------------------
> drivers/hwmon/ams/ams-input.c | 157 --------------------
> drivers/hwmon/ams/ams-pmu.c | 201 --------------------------
> drivers/hwmon/ams/ams.h | 70 ---------
> drivers/macintosh/Kconfig | 26 +++
> drivers/macintosh/Makefile | 2
> drivers/macintosh/ams/Makefile | 8 +
> drivers/macintosh/ams/ams-core.c | 250 +++++++++++++++++++++++++++++++++
> drivers/macintosh/ams/ams-i2c.c | 277 +++++++++++++++++++++++++++++++++++++
> drivers/macintosh/ams/ams-input.c | 157 ++++++++++++++++++++
> drivers/macintosh/ams/ams-pmu.c | 201 ++++++++++++++++++++++++++
> drivers/macintosh/ams/ams.h | 70 +++++++++
> 17 files changed, 992 insertions(+), 991 deletions(-)
>
> --- linux-2.6.36-rc6.orig/drivers/hwmon/ams/Makefile 2010-08-02 00:11:14.000000000 +0200
> +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
> @@ -1,8 +0,0 @@
> -#
> -# Makefile for Apple Motion Sensor driver
> -#
> -
> -ams-y := ams-core.o ams-input.o
> -ams-$(CONFIG_SENSORS_AMS_PMU) += ams-pmu.o
> -ams-$(CONFIG_SENSORS_AMS_I2C) += ams-i2c.o
> -obj-$(CONFIG_SENSORS_AMS) += ams.o
> --- linux-2.6.36-rc6.orig/drivers/hwmon/ams/ams-core.c 2010-08-02 00:11:14.000000000 +0200
> +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
> @@ -1,250 +0,0 @@
> -/*
> - * Apple Motion Sensor driver
> - *
> - * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
> - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/types.h>
> -#include <linux/errno.h>
> -#include <linux/init.h>
> -#include <linux/of_platform.h>
> -#include <asm/pmac_pfunc.h>
> -
> -#include "ams.h"
> -
> -/* There is only one motion sensor per machine */
> -struct ams ams_info;
> -
> -static unsigned int verbose;
> -module_param(verbose, bool, 0644);
> -MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
> -
> -/* Call with ams_info.lock held! */
> -void ams_sensors(s8 *x, s8 *y, s8 *z)
> -{
> - u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
> -
> - if (orient & 0x80)
> - /* X and Y swapped */
> - ams_info.get_xyz(y, x, z);
> - else
> - ams_info.get_xyz(x, y, z);
> -
> - if (orient & 0x04)
> - *z = ~(*z);
> - if (orient & 0x02)
> - *y = ~(*y);
> - if (orient & 0x01)
> - *x = ~(*x);
> -}
> -
> -static ssize_t ams_show_current(struct device *dev,
> - struct device_attribute *attr, char *buf)
> -{
> - s8 x, y, z;
> -
> - mutex_lock(&ams_info.lock);
> - ams_sensors(&x, &y, &z);
> - mutex_unlock(&ams_info.lock);
> -
> - return snprintf(buf, PAGE_SIZE, "%d %d %d\n", x, y, z);
> -}
> -
> -static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
> -
> -static void ams_handle_irq(void *data)
> -{
> - enum ams_irq irq = *((enum ams_irq *)data);
> -
> - spin_lock(&ams_info.irq_lock);
> -
> - ams_info.worker_irqs |= irq;
> - schedule_work(&ams_info.worker);
> -
> - spin_unlock(&ams_info.irq_lock);
> -}
> -
> -static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
> -static struct pmf_irq_client ams_freefall_client = {
> - .owner = THIS_MODULE,
> - .handler = ams_handle_irq,
> - .data = &ams_freefall_irq_data,
> -};
> -
> -static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
> -static struct pmf_irq_client ams_shock_client = {
> - .owner = THIS_MODULE,
> - .handler = ams_handle_irq,
> - .data = &ams_shock_irq_data,
> -};
> -
> -/* Once hard disk parking is implemented in the kernel, this function can
> - * trigger it.
> - */
> -static void ams_worker(struct work_struct *work)
> -{
> - unsigned long flags;
> - u8 irqs_to_clear;
> -
> - mutex_lock(&ams_info.lock);
> -
> - spin_lock_irqsave(&ams_info.irq_lock, flags);
> - irqs_to_clear = ams_info.worker_irqs;
> -
> - if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
> - if (verbose)
> - printk(KERN_INFO "ams: freefall detected!\n");
> -
> - ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
> - }
> -
> - if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
> - if (verbose)
> - printk(KERN_INFO "ams: shock detected!\n");
> -
> - ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
> - }
> -
> - spin_unlock_irqrestore(&ams_info.irq_lock, flags);
> -
> - ams_info.clear_irq(irqs_to_clear);
> -
> - mutex_unlock(&ams_info.lock);
> -}
> -
> -/* Call with ams_info.lock held! */
> -int ams_sensor_attach(void)
> -{
> - int result;
> - const u32 *prop;
> -
> - /* Get orientation */
> - prop = of_get_property(ams_info.of_node, "orientation", NULL);
> - if (!prop)
> - return -ENODEV;
> - ams_info.orient1 = *prop;
> - ams_info.orient2 = *(prop + 1);
> -
> - /* Register freefall interrupt handler */
> - result = pmf_register_irq_client(ams_info.of_node,
> - "accel-int-1",
> - &ams_freefall_client);
> - if (result < 0)
> - return -ENODEV;
> -
> - /* Reset saved irqs */
> - ams_info.worker_irqs = 0;
> -
> - /* Register shock interrupt handler */
> - result = pmf_register_irq_client(ams_info.of_node,
> - "accel-int-2",
> - &ams_shock_client);
> - if (result < 0)
> - goto release_freefall;
> -
> - /* Create device */
> - ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
> - if (!ams_info.of_dev) {
> - result = -ENODEV;
> - goto release_shock;
> - }
> -
> - /* Create attributes */
> - result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
> - if (result)
> - goto release_of;
> -
> - ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
> -
> - /* Init input device */
> - result = ams_input_init();
> - if (result)
> - goto release_device_file;
> -
> - return result;
> -release_device_file:
> - device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
> -release_of:
> - of_device_unregister(ams_info.of_dev);
> -release_shock:
> - pmf_unregister_irq_client(&ams_shock_client);
> -release_freefall:
> - pmf_unregister_irq_client(&ams_freefall_client);
> - return result;
> -}
> -
> -int __init ams_init(void)
> -{
> - struct device_node *np;
> -
> - spin_lock_init(&ams_info.irq_lock);
> - mutex_init(&ams_info.lock);
> - INIT_WORK(&ams_info.worker, ams_worker);
> -
> -#ifdef CONFIG_SENSORS_AMS_I2C
> - np = of_find_node_by_name(NULL, "accelerometer");
> - if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
> - /* Found I2C motion sensor */
> - return ams_i2c_init(np);
> -#endif
> -
> -#ifdef CONFIG_SENSORS_AMS_PMU
> - np = of_find_node_by_name(NULL, "sms");
> - if (np && of_device_is_compatible(np, "sms"))
> - /* Found PMU motion sensor */
> - return ams_pmu_init(np);
> -#endif
> - return -ENODEV;
> -}
> -
> -void ams_sensor_detach(void)
> -{
> - /* Remove input device */
> - ams_input_exit();
> -
> - /* Remove attributes */
> - device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
> -
> - /* Flush interrupt worker
> - *
> - * We do this after ams_info.exit(), because an interrupt might
> - * have arrived before disabling them.
> - */
> - flush_scheduled_work();
> -
> - /* Remove device */
> - of_device_unregister(ams_info.of_dev);
> -
> - /* Remove handler */
> - pmf_unregister_irq_client(&ams_shock_client);
> - pmf_unregister_irq_client(&ams_freefall_client);
> -}
> -
> -static void __exit ams_exit(void)
> -{
> - /* Shut down implementation */
> - ams_info.exit();
> -}
> -
> -MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
> -MODULE_DESCRIPTION("Apple Motion Sensor driver");
> -MODULE_LICENSE("GPL");
> -
> -module_init(ams_init);
> -module_exit(ams_exit);
> --- linux-2.6.36-rc6.orig/drivers/hwmon/ams/ams-i2c.c 2010-08-02 00:11:14.000000000 +0200
> +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
> @@ -1,277 +0,0 @@
> -/*
> - * Apple Motion Sensor driver (I2C variant)
> - *
> - * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
> - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> - *
> - * Clean room implementation based on the reverse engineered Mac OS X driver by
> - * Johannes Berg <johannes@sipsolutions.net>, documentation available at
> - * http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/types.h>
> -#include <linux/errno.h>
> -#include <linux/init.h>
> -#include <linux/delay.h>
> -
> -#include "ams.h"
> -
> -/* AMS registers */
> -#define AMS_COMMAND 0x00 /* command register */
> -#define AMS_STATUS 0x01 /* status register */
> -#define AMS_CTRL1 0x02 /* read control 1 (number of values) */
> -#define AMS_CTRL2 0x03 /* read control 2 (offset?) */
> -#define AMS_CTRL3 0x04 /* read control 3 (size of each value?) */
> -#define AMS_DATA1 0x05 /* read data 1 */
> -#define AMS_DATA2 0x06 /* read data 2 */
> -#define AMS_DATA3 0x07 /* read data 3 */
> -#define AMS_DATA4 0x08 /* read data 4 */
> -#define AMS_DATAX 0x20 /* data X */
> -#define AMS_DATAY 0x21 /* data Y */
> -#define AMS_DATAZ 0x22 /* data Z */
> -#define AMS_FREEFALL 0x24 /* freefall int control */
> -#define AMS_SHOCK 0x25 /* shock int control */
> -#define AMS_SENSLOW 0x26 /* sensitivity low limit */
> -#define AMS_SENSHIGH 0x27 /* sensitivity high limit */
> -#define AMS_CTRLX 0x28 /* control X */
> -#define AMS_CTRLY 0x29 /* control Y */
> -#define AMS_CTRLZ 0x2A /* control Z */
> -#define AMS_UNKNOWN1 0x2B /* unknown 1 */
> -#define AMS_UNKNOWN2 0x2C /* unknown 2 */
> -#define AMS_UNKNOWN3 0x2D /* unknown 3 */
> -#define AMS_VENDOR 0x2E /* vendor */
> -
> -/* AMS commands - use with the AMS_COMMAND register */
> -enum ams_i2c_cmd {
> - AMS_CMD_NOOP = 0,
> - AMS_CMD_VERSION,
> - AMS_CMD_READMEM,
> - AMS_CMD_WRITEMEM,
> - AMS_CMD_ERASEMEM,
> - AMS_CMD_READEE,
> - AMS_CMD_WRITEEE,
> - AMS_CMD_RESET,
> - AMS_CMD_START,
> -};
> -
> -static int ams_i2c_probe(struct i2c_client *client,
> - const struct i2c_device_id *id);
> -static int ams_i2c_remove(struct i2c_client *client);
> -
> -static const struct i2c_device_id ams_id[] = {
> - { "ams", 0 },
> - { }
> -};
> -MODULE_DEVICE_TABLE(i2c, ams_id);
> -
> -static struct i2c_driver ams_i2c_driver = {
> - .driver = {
> - .name = "ams",
> - .owner = THIS_MODULE,
> - },
> - .probe = ams_i2c_probe,
> - .remove = ams_i2c_remove,
> - .id_table = ams_id,
> -};
> -
> -static s32 ams_i2c_read(u8 reg)
> -{
> - return i2c_smbus_read_byte_data(ams_info.i2c_client, reg);
> -}
> -
> -static int ams_i2c_write(u8 reg, u8 value)
> -{
> - return i2c_smbus_write_byte_data(ams_info.i2c_client, reg, value);
> -}
> -
> -static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
> -{
> - s32 result;
> - int count = 3;
> -
> - ams_i2c_write(AMS_COMMAND, cmd);
> - msleep(5);
> -
> - while (count--) {
> - result = ams_i2c_read(AMS_COMMAND);
> - if (result == 0 || result & 0x80)
> - return 0;
> -
> - schedule_timeout_uninterruptible(HZ / 20);
> - }
> -
> - return -1;
> -}
> -
> -static void ams_i2c_set_irq(enum ams_irq reg, char enable)
> -{
> - if (reg & AMS_IRQ_FREEFALL) {
> - u8 val = ams_i2c_read(AMS_CTRLX);
> - if (enable)
> - val |= 0x80;
> - else
> - val &= ~0x80;
> - ams_i2c_write(AMS_CTRLX, val);
> - }
> -
> - if (reg & AMS_IRQ_SHOCK) {
> - u8 val = ams_i2c_read(AMS_CTRLY);
> - if (enable)
> - val |= 0x80;
> - else
> - val &= ~0x80;
> - ams_i2c_write(AMS_CTRLY, val);
> - }
> -
> - if (reg & AMS_IRQ_GLOBAL) {
> - u8 val = ams_i2c_read(AMS_CTRLZ);
> - if (enable)
> - val |= 0x80;
> - else
> - val &= ~0x80;
> - ams_i2c_write(AMS_CTRLZ, val);
> - }
> -}
> -
> -static void ams_i2c_clear_irq(enum ams_irq reg)
> -{
> - if (reg & AMS_IRQ_FREEFALL)
> - ams_i2c_write(AMS_FREEFALL, 0);
> -
> - if (reg & AMS_IRQ_SHOCK)
> - ams_i2c_write(AMS_SHOCK, 0);
> -}
> -
> -static u8 ams_i2c_get_vendor(void)
> -{
> - return ams_i2c_read(AMS_VENDOR);
> -}
> -
> -static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z)
> -{
> - *x = ams_i2c_read(AMS_DATAX);
> - *y = ams_i2c_read(AMS_DATAY);
> - *z = ams_i2c_read(AMS_DATAZ);
> -}
> -
> -static int ams_i2c_probe(struct i2c_client *client,
> - const struct i2c_device_id *id)
> -{
> - int vmaj, vmin;
> - int result;
> -
> - /* There can be only one */
> - if (unlikely(ams_info.has_device))
> - return -ENODEV;
> -
> - ams_info.i2c_client = client;
> -
> - if (ams_i2c_cmd(AMS_CMD_RESET)) {
> - printk(KERN_INFO "ams: Failed to reset the device\n");
> - return -ENODEV;
> - }
> -
> - if (ams_i2c_cmd(AMS_CMD_START)) {
> - printk(KERN_INFO "ams: Failed to start the device\n");
> - return -ENODEV;
> - }
> -
> - /* get version/vendor information */
> - ams_i2c_write(AMS_CTRL1, 0x02);
> - ams_i2c_write(AMS_CTRL2, 0x85);
> - ams_i2c_write(AMS_CTRL3, 0x01);
> -
> - ams_i2c_cmd(AMS_CMD_READMEM);
> -
> - vmaj = ams_i2c_read(AMS_DATA1);
> - vmin = ams_i2c_read(AMS_DATA2);
> - if (vmaj != 1 || vmin != 52) {
> - printk(KERN_INFO "ams: Incorrect device version (%d.%d)\n",
> - vmaj, vmin);
> - return -ENODEV;
> - }
> -
> - ams_i2c_cmd(AMS_CMD_VERSION);
> -
> - vmaj = ams_i2c_read(AMS_DATA1);
> - vmin = ams_i2c_read(AMS_DATA2);
> - if (vmaj != 0 || vmin != 1) {
> - printk(KERN_INFO "ams: Incorrect firmware version (%d.%d)\n",
> - vmaj, vmin);
> - return -ENODEV;
> - }
> -
> - /* Disable interrupts */
> - ams_i2c_set_irq(AMS_IRQ_ALL, 0);
> -
> - result = ams_sensor_attach();
> - if (result < 0)
> - return result;
> -
> - /* Set default values */
> - ams_i2c_write(AMS_SENSLOW, 0x15);
> - ams_i2c_write(AMS_SENSHIGH, 0x60);
> - ams_i2c_write(AMS_CTRLX, 0x08);
> - ams_i2c_write(AMS_CTRLY, 0x0F);
> - ams_i2c_write(AMS_CTRLZ, 0x4F);
> - ams_i2c_write(AMS_UNKNOWN1, 0x14);
> -
> - /* Clear interrupts */
> - ams_i2c_clear_irq(AMS_IRQ_ALL);
> -
> - ams_info.has_device = 1;
> -
> - /* Enable interrupts */
> - ams_i2c_set_irq(AMS_IRQ_ALL, 1);
> -
> - printk(KERN_INFO "ams: Found I2C based motion sensor\n");
> -
> - return 0;
> -}
> -
> -static int ams_i2c_remove(struct i2c_client *client)
> -{
> - if (ams_info.has_device) {
> - ams_sensor_detach();
> -
> - /* Disable interrupts */
> - ams_i2c_set_irq(AMS_IRQ_ALL, 0);
> -
> - /* Clear interrupts */
> - ams_i2c_clear_irq(AMS_IRQ_ALL);
> -
> - printk(KERN_INFO "ams: Unloading\n");
> -
> - ams_info.has_device = 0;
> - }
> -
> - return 0;
> -}
> -
> -static void ams_i2c_exit(void)
> -{
> - i2c_del_driver(&ams_i2c_driver);
> -}
> -
> -int __init ams_i2c_init(struct device_node *np)
> -{
> - int result;
> -
> - /* Set implementation stuff */
> - ams_info.of_node = np;
> - ams_info.exit = ams_i2c_exit;
> - ams_info.get_vendor = ams_i2c_get_vendor;
> - ams_info.get_xyz = ams_i2c_get_xyz;
> - ams_info.clear_irq = ams_i2c_clear_irq;
> - ams_info.bustype = BUS_I2C;
> -
> - result = i2c_add_driver(&ams_i2c_driver);
> -
> - return result;
> -}
> --- linux-2.6.36-rc6.orig/drivers/hwmon/ams/ams-input.c 2010-08-02 00:11:14.000000000 +0200
> +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
> @@ -1,157 +0,0 @@
> -/*
> - * Apple Motion Sensor driver (joystick emulation)
> - *
> - * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
> - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - */
> -
> -#include <linux/module.h>
> -
> -#include <linux/types.h>
> -#include <linux/errno.h>
> -#include <linux/init.h>
> -#include <linux/delay.h>
> -
> -#include "ams.h"
> -
> -static unsigned int joystick;
> -module_param(joystick, bool, S_IRUGO);
> -MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
> -
> -static unsigned int invert;
> -module_param(invert, bool, S_IWUSR | S_IRUGO);
> -MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
> -
> -static DEFINE_MUTEX(ams_input_mutex);
> -
> -static void ams_idev_poll(struct input_polled_dev *dev)
> -{
> - struct input_dev *idev = dev->input;
> - s8 x, y, z;
> -
> - mutex_lock(&ams_info.lock);
> -
> - ams_sensors(&x, &y, &z);
> -
> - x -= ams_info.xcalib;
> - y -= ams_info.ycalib;
> - z -= ams_info.zcalib;
> -
> - input_report_abs(idev, ABS_X, invert ? -x : x);
> - input_report_abs(idev, ABS_Y, invert ? -y : y);
> - input_report_abs(idev, ABS_Z, z);
> -
> - input_sync(idev);
> -
> - mutex_unlock(&ams_info.lock);
> -}
> -
> -/* Call with ams_info.lock held! */
> -static int ams_input_enable(void)
> -{
> - struct input_dev *input;
> - s8 x, y, z;
> - int error;
> -
> - ams_sensors(&x, &y, &z);
> - ams_info.xcalib = x;
> - ams_info.ycalib = y;
> - ams_info.zcalib = z;
> -
> - ams_info.idev = input_allocate_polled_device();
> - if (!ams_info.idev)
> - return -ENOMEM;
> -
> - ams_info.idev->poll = ams_idev_poll;
> - ams_info.idev->poll_interval = 25;
> -
> - input = ams_info.idev->input;
> - input->name = "Apple Motion Sensor";
> - input->id.bustype = ams_info.bustype;
> - input->id.vendor = 0;
> - input->dev.parent = &ams_info.of_dev->dev;
> -
> - input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
> - input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
> - input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
> -
> - set_bit(EV_ABS, input->evbit);
> - set_bit(EV_KEY, input->evbit);
> - set_bit(BTN_TOUCH, input->keybit);
> -
> - error = input_register_polled_device(ams_info.idev);
> - if (error) {
> - input_free_polled_device(ams_info.idev);
> - ams_info.idev = NULL;
> - return error;
> - }
> -
> - joystick = 1;
> -
> - return 0;
> -}
> -
> -static void ams_input_disable(void)
> -{
> - if (ams_info.idev) {
> - input_unregister_polled_device(ams_info.idev);
> - input_free_polled_device(ams_info.idev);
> - ams_info.idev = NULL;
> - }
> -
> - joystick = 0;
> -}
> -
> -static ssize_t ams_input_show_joystick(struct device *dev,
> - struct device_attribute *attr, char *buf)
> -{
> - return sprintf(buf, "%d\n", joystick);
> -}
> -
> -static ssize_t ams_input_store_joystick(struct device *dev,
> - struct device_attribute *attr, const char *buf, size_t count)
> -{
> - unsigned long enable;
> - int error = 0;
> -
> - if (strict_strtoul(buf, 0, &enable) || enable > 1)
> - return -EINVAL;
> -
> - mutex_lock(&ams_input_mutex);
> -
> - if (enable != joystick) {
> - if (enable)
> - error = ams_input_enable();
> - else
> - ams_input_disable();
> - }
> -
> - mutex_unlock(&ams_input_mutex);
> -
> - return error ? error : count;
> -}
> -
> -static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
> - ams_input_show_joystick, ams_input_store_joystick);
> -
> -int ams_input_init(void)
> -{
> - if (joystick)
> - ams_input_enable();
> -
> - return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
> -}
> -
> -void ams_input_exit(void)
> -{
> - device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
> -
> - mutex_lock(&ams_input_mutex);
> - ams_input_disable();
> - mutex_unlock(&ams_input_mutex);
> -}
> --- linux-2.6.36-rc6.orig/drivers/hwmon/ams/ams-pmu.c 2010-08-02 00:11:14.000000000 +0200
> +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
> @@ -1,201 +0,0 @@
> -/*
> - * Apple Motion Sensor driver (PMU variant)
> - *
> - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/types.h>
> -#include <linux/errno.h>
> -#include <linux/init.h>
> -#include <linux/adb.h>
> -#include <linux/pmu.h>
> -
> -#include "ams.h"
> -
> -/* Attitude */
> -#define AMS_X 0x00
> -#define AMS_Y 0x01
> -#define AMS_Z 0x02
> -
> -/* Not exactly known, maybe chip vendor */
> -#define AMS_VENDOR 0x03
> -
> -/* Freefall registers */
> -#define AMS_FF_CLEAR 0x04
> -#define AMS_FF_ENABLE 0x05
> -#define AMS_FF_LOW_LIMIT 0x06
> -#define AMS_FF_DEBOUNCE 0x07
> -
> -/* Shock registers */
> -#define AMS_SHOCK_CLEAR 0x08
> -#define AMS_SHOCK_ENABLE 0x09
> -#define AMS_SHOCK_HIGH_LIMIT 0x0a
> -#define AMS_SHOCK_DEBOUNCE 0x0b
> -
> -/* Global interrupt and power control register */
> -#define AMS_CONTROL 0x0c
> -
> -static u8 ams_pmu_cmd;
> -
> -static void ams_pmu_req_complete(struct adb_request *req)
> -{
> - complete((struct completion *)req->arg);
> -}
> -
> -/* Only call this function from task context */
> -static void ams_pmu_set_register(u8 reg, u8 value)
> -{
> - static struct adb_request req;
> - DECLARE_COMPLETION(req_complete);
> -
> - req.arg = &req_complete;
> - if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
> - return;
> -
> - wait_for_completion(&req_complete);
> -}
> -
> -/* Only call this function from task context */
> -static u8 ams_pmu_get_register(u8 reg)
> -{
> - static struct adb_request req;
> - DECLARE_COMPLETION(req_complete);
> -
> - req.arg = &req_complete;
> - if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
> - return 0;
> -
> - wait_for_completion(&req_complete);
> -
> - if (req.reply_len > 0)
> - return req.reply[0];
> - else
> - return 0;
> -}
> -
> -/* Enables or disables the specified interrupts */
> -static void ams_pmu_set_irq(enum ams_irq reg, char enable)
> -{
> - if (reg & AMS_IRQ_FREEFALL) {
> - u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
> - if (enable)
> - val |= 0x80;
> - else
> - val &= ~0x80;
> - ams_pmu_set_register(AMS_FF_ENABLE, val);
> - }
> -
> - if (reg & AMS_IRQ_SHOCK) {
> - u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
> - if (enable)
> - val |= 0x80;
> - else
> - val &= ~0x80;
> - ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
> - }
> -
> - if (reg & AMS_IRQ_GLOBAL) {
> - u8 val = ams_pmu_get_register(AMS_CONTROL);
> - if (enable)
> - val |= 0x80;
> - else
> - val &= ~0x80;
> - ams_pmu_set_register(AMS_CONTROL, val);
> - }
> -}
> -
> -static void ams_pmu_clear_irq(enum ams_irq reg)
> -{
> - if (reg & AMS_IRQ_FREEFALL)
> - ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
> -
> - if (reg & AMS_IRQ_SHOCK)
> - ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
> -}
> -
> -static u8 ams_pmu_get_vendor(void)
> -{
> - return ams_pmu_get_register(AMS_VENDOR);
> -}
> -
> -static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
> -{
> - *x = ams_pmu_get_register(AMS_X);
> - *y = ams_pmu_get_register(AMS_Y);
> - *z = ams_pmu_get_register(AMS_Z);
> -}
> -
> -static void ams_pmu_exit(void)
> -{
> - ams_sensor_detach();
> -
> - /* Disable interrupts */
> - ams_pmu_set_irq(AMS_IRQ_ALL, 0);
> -
> - /* Clear interrupts */
> - ams_pmu_clear_irq(AMS_IRQ_ALL);
> -
> - ams_info.has_device = 0;
> -
> - printk(KERN_INFO "ams: Unloading\n");
> -}
> -
> -int __init ams_pmu_init(struct device_node *np)
> -{
> - const u32 *prop;
> - int result;
> -
> - /* Set implementation stuff */
> - ams_info.of_node = np;
> - ams_info.exit = ams_pmu_exit;
> - ams_info.get_vendor = ams_pmu_get_vendor;
> - ams_info.get_xyz = ams_pmu_get_xyz;
> - ams_info.clear_irq = ams_pmu_clear_irq;
> - ams_info.bustype = BUS_HOST;
> -
> - /* Get PMU command, should be 0x4e, but we can never know */
> - prop = of_get_property(ams_info.of_node, "reg", NULL);
> - if (!prop)
> - return -ENODEV;
> -
> - ams_pmu_cmd = ((*prop) >> 8) & 0xff;
> -
> - /* Disable interrupts */
> - ams_pmu_set_irq(AMS_IRQ_ALL, 0);
> -
> - /* Clear interrupts */
> - ams_pmu_clear_irq(AMS_IRQ_ALL);
> -
> - result = ams_sensor_attach();
> - if (result < 0)
> - return result;
> -
> - /* Set default values */
> - ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
> - ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
> - ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
> -
> - ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
> - ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
> - ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
> -
> - ams_pmu_set_register(AMS_CONTROL, 0x4f);
> -
> - /* Clear interrupts */
> - ams_pmu_clear_irq(AMS_IRQ_ALL);
> -
> - ams_info.has_device = 1;
> -
> - /* Enable interrupts */
> - ams_pmu_set_irq(AMS_IRQ_ALL, 1);
> -
> - printk(KERN_INFO "ams: Found PMU based motion sensor\n");
> -
> - return 0;
> -}
> --- linux-2.6.36-rc6.orig/drivers/hwmon/ams/ams.h 2010-09-21 11:07:14.000000000 +0200
> +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
> @@ -1,70 +0,0 @@
> -#include <linux/i2c.h>
> -#include <linux/input-polldev.h>
> -#include <linux/kthread.h>
> -#include <linux/mutex.h>
> -#include <linux/spinlock.h>
> -#include <linux/types.h>
> -#include <linux/of_device.h>
> -
> -enum ams_irq {
> - AMS_IRQ_FREEFALL = 0x01,
> - AMS_IRQ_SHOCK = 0x02,
> - AMS_IRQ_GLOBAL = 0x04,
> - AMS_IRQ_ALL =
> - AMS_IRQ_FREEFALL |
> - AMS_IRQ_SHOCK |
> - AMS_IRQ_GLOBAL,
> -};
> -
> -struct ams {
> - /* Locks */
> - spinlock_t irq_lock;
> - struct mutex lock;
> -
> - /* General properties */
> - struct device_node *of_node;
> - struct platform_device *of_dev;
> - char has_device;
> - char vflag;
> - u32 orient1;
> - u32 orient2;
> -
> - /* Interrupt worker */
> - struct work_struct worker;
> - u8 worker_irqs;
> -
> - /* Implementation
> - *
> - * Only call these functions with the main lock held.
> - */
> - void (*exit)(void);
> -
> - void (*get_xyz)(s8 *x, s8 *y, s8 *z);
> - u8 (*get_vendor)(void);
> -
> - void (*clear_irq)(enum ams_irq reg);
> -
> -#ifdef CONFIG_SENSORS_AMS_I2C
> - /* I2C properties */
> - struct i2c_client *i2c_client;
> -#endif
> -
> - /* Joystick emulation */
> - struct input_polled_dev *idev;
> - __u16 bustype;
> -
> - /* calibrated null values */
> - int xcalib, ycalib, zcalib;
> -};
> -
> -extern struct ams ams_info;
> -
> -extern void ams_sensors(s8 *x, s8 *y, s8 *z);
> -extern int ams_sensor_attach(void);
> -extern void ams_sensor_detach(void);
> -
> -extern int ams_pmu_init(struct device_node *np);
> -extern int ams_i2c_init(struct device_node *np);
> -
> -extern int ams_input_init(void);
> -extern void ams_input_exit(void);
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.36-rc6/drivers/macintosh/ams/Makefile 2010-08-02 00:11:14.000000000 +0200
> @@ -0,0 +1,8 @@
> +#
> +# Makefile for Apple Motion Sensor driver
> +#
> +
> +ams-y := ams-core.o ams-input.o
> +ams-$(CONFIG_SENSORS_AMS_PMU) += ams-pmu.o
> +ams-$(CONFIG_SENSORS_AMS_I2C) += ams-i2c.o
> +obj-$(CONFIG_SENSORS_AMS) += ams.o
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.36-rc6/drivers/macintosh/ams/ams-core.c 2010-08-02 00:11:14.000000000 +0200
> @@ -0,0 +1,250 @@
> +/*
> + * Apple Motion Sensor driver
> + *
> + * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
> + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/of_platform.h>
> +#include <asm/pmac_pfunc.h>
> +
> +#include "ams.h"
> +
> +/* There is only one motion sensor per machine */
> +struct ams ams_info;
> +
> +static unsigned int verbose;
> +module_param(verbose, bool, 0644);
> +MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
> +
> +/* Call with ams_info.lock held! */
> +void ams_sensors(s8 *x, s8 *y, s8 *z)
> +{
> + u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
> +
> + if (orient & 0x80)
> + /* X and Y swapped */
> + ams_info.get_xyz(y, x, z);
> + else
> + ams_info.get_xyz(x, y, z);
> +
> + if (orient & 0x04)
> + *z = ~(*z);
> + if (orient & 0x02)
> + *y = ~(*y);
> + if (orient & 0x01)
> + *x = ~(*x);
> +}
> +
> +static ssize_t ams_show_current(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + s8 x, y, z;
> +
> + mutex_lock(&ams_info.lock);
> + ams_sensors(&x, &y, &z);
> + mutex_unlock(&ams_info.lock);
> +
> + return snprintf(buf, PAGE_SIZE, "%d %d %d\n", x, y, z);
> +}
> +
> +static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
> +
> +static void ams_handle_irq(void *data)
> +{
> + enum ams_irq irq = *((enum ams_irq *)data);
> +
> + spin_lock(&ams_info.irq_lock);
> +
> + ams_info.worker_irqs |= irq;
> + schedule_work(&ams_info.worker);
> +
> + spin_unlock(&ams_info.irq_lock);
> +}
> +
> +static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
> +static struct pmf_irq_client ams_freefall_client = {
> + .owner = THIS_MODULE,
> + .handler = ams_handle_irq,
> + .data = &ams_freefall_irq_data,
> +};
> +
> +static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
> +static struct pmf_irq_client ams_shock_client = {
> + .owner = THIS_MODULE,
> + .handler = ams_handle_irq,
> + .data = &ams_shock_irq_data,
> +};
> +
> +/* Once hard disk parking is implemented in the kernel, this function can
> + * trigger it.
> + */
> +static void ams_worker(struct work_struct *work)
> +{
> + unsigned long flags;
> + u8 irqs_to_clear;
> +
> + mutex_lock(&ams_info.lock);
> +
> + spin_lock_irqsave(&ams_info.irq_lock, flags);
> + irqs_to_clear = ams_info.worker_irqs;
> +
> + if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
> + if (verbose)
> + printk(KERN_INFO "ams: freefall detected!\n");
> +
> + ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
> + }
> +
> + if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
> + if (verbose)
> + printk(KERN_INFO "ams: shock detected!\n");
> +
> + ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
> + }
> +
> + spin_unlock_irqrestore(&ams_info.irq_lock, flags);
> +
> + ams_info.clear_irq(irqs_to_clear);
> +
> + mutex_unlock(&ams_info.lock);
> +}
> +
> +/* Call with ams_info.lock held! */
> +int ams_sensor_attach(void)
> +{
> + int result;
> + const u32 *prop;
> +
> + /* Get orientation */
> + prop = of_get_property(ams_info.of_node, "orientation", NULL);
> + if (!prop)
> + return -ENODEV;
> + ams_info.orient1 = *prop;
> + ams_info.orient2 = *(prop + 1);
> +
> + /* Register freefall interrupt handler */
> + result = pmf_register_irq_client(ams_info.of_node,
> + "accel-int-1",
> + &ams_freefall_client);
> + if (result < 0)
> + return -ENODEV;
> +
> + /* Reset saved irqs */
> + ams_info.worker_irqs = 0;
> +
> + /* Register shock interrupt handler */
> + result = pmf_register_irq_client(ams_info.of_node,
> + "accel-int-2",
> + &ams_shock_client);
> + if (result < 0)
> + goto release_freefall;
> +
> + /* Create device */
> + ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
> + if (!ams_info.of_dev) {
> + result = -ENODEV;
> + goto release_shock;
> + }
> +
> + /* Create attributes */
> + result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
> + if (result)
> + goto release_of;
> +
> + ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
> +
> + /* Init input device */
> + result = ams_input_init();
> + if (result)
> + goto release_device_file;
> +
> + return result;
> +release_device_file:
> + device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
> +release_of:
> + of_device_unregister(ams_info.of_dev);
> +release_shock:
> + pmf_unregister_irq_client(&ams_shock_client);
> +release_freefall:
> + pmf_unregister_irq_client(&ams_freefall_client);
> + return result;
> +}
> +
> +int __init ams_init(void)
> +{
> + struct device_node *np;
> +
> + spin_lock_init(&ams_info.irq_lock);
> + mutex_init(&ams_info.lock);
> + INIT_WORK(&ams_info.worker, ams_worker);
> +
> +#ifdef CONFIG_SENSORS_AMS_I2C
> + np = of_find_node_by_name(NULL, "accelerometer");
> + if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
> + /* Found I2C motion sensor */
> + return ams_i2c_init(np);
> +#endif
> +
> +#ifdef CONFIG_SENSORS_AMS_PMU
> + np = of_find_node_by_name(NULL, "sms");
> + if (np && of_device_is_compatible(np, "sms"))
> + /* Found PMU motion sensor */
> + return ams_pmu_init(np);
> +#endif
> + return -ENODEV;
> +}
> +
> +void ams_sensor_detach(void)
> +{
> + /* Remove input device */
> + ams_input_exit();
> +
> + /* Remove attributes */
> + device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
> +
> + /* Flush interrupt worker
> + *
> + * We do this after ams_info.exit(), because an interrupt might
> + * have arrived before disabling them.
> + */
> + flush_scheduled_work();
> +
> + /* Remove device */
> + of_device_unregister(ams_info.of_dev);
> +
> + /* Remove handler */
> + pmf_unregister_irq_client(&ams_shock_client);
> + pmf_unregister_irq_client(&ams_freefall_client);
> +}
> +
> +static void __exit ams_exit(void)
> +{
> + /* Shut down implementation */
> + ams_info.exit();
> +}
> +
> +MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
> +MODULE_DESCRIPTION("Apple Motion Sensor driver");
> +MODULE_LICENSE("GPL");
> +
> +module_init(ams_init);
> +module_exit(ams_exit);
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.36-rc6/drivers/macintosh/ams/ams-i2c.c 2010-08-02 00:11:14.000000000 +0200
> @@ -0,0 +1,277 @@
> +/*
> + * Apple Motion Sensor driver (I2C variant)
> + *
> + * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
> + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> + *
> + * Clean room implementation based on the reverse engineered Mac OS X driver by
> + * Johannes Berg <johannes@sipsolutions.net>, documentation available at
> + * http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +
> +#include "ams.h"
> +
> +/* AMS registers */
> +#define AMS_COMMAND 0x00 /* command register */
> +#define AMS_STATUS 0x01 /* status register */
> +#define AMS_CTRL1 0x02 /* read control 1 (number of values) */
> +#define AMS_CTRL2 0x03 /* read control 2 (offset?) */
> +#define AMS_CTRL3 0x04 /* read control 3 (size of each value?) */
> +#define AMS_DATA1 0x05 /* read data 1 */
> +#define AMS_DATA2 0x06 /* read data 2 */
> +#define AMS_DATA3 0x07 /* read data 3 */
> +#define AMS_DATA4 0x08 /* read data 4 */
> +#define AMS_DATAX 0x20 /* data X */
> +#define AMS_DATAY 0x21 /* data Y */
> +#define AMS_DATAZ 0x22 /* data Z */
> +#define AMS_FREEFALL 0x24 /* freefall int control */
> +#define AMS_SHOCK 0x25 /* shock int control */
> +#define AMS_SENSLOW 0x26 /* sensitivity low limit */
> +#define AMS_SENSHIGH 0x27 /* sensitivity high limit */
> +#define AMS_CTRLX 0x28 /* control X */
> +#define AMS_CTRLY 0x29 /* control Y */
> +#define AMS_CTRLZ 0x2A /* control Z */
> +#define AMS_UNKNOWN1 0x2B /* unknown 1 */
> +#define AMS_UNKNOWN2 0x2C /* unknown 2 */
> +#define AMS_UNKNOWN3 0x2D /* unknown 3 */
> +#define AMS_VENDOR 0x2E /* vendor */
> +
> +/* AMS commands - use with the AMS_COMMAND register */
> +enum ams_i2c_cmd {
> + AMS_CMD_NOOP = 0,
> + AMS_CMD_VERSION,
> + AMS_CMD_READMEM,
> + AMS_CMD_WRITEMEM,
> + AMS_CMD_ERASEMEM,
> + AMS_CMD_READEE,
> + AMS_CMD_WRITEEE,
> + AMS_CMD_RESET,
> + AMS_CMD_START,
> +};
> +
> +static int ams_i2c_probe(struct i2c_client *client,
> + const struct i2c_device_id *id);
> +static int ams_i2c_remove(struct i2c_client *client);
> +
> +static const struct i2c_device_id ams_id[] = {
> + { "ams", 0 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, ams_id);
> +
> +static struct i2c_driver ams_i2c_driver = {
> + .driver = {
> + .name = "ams",
> + .owner = THIS_MODULE,
> + },
> + .probe = ams_i2c_probe,
> + .remove = ams_i2c_remove,
> + .id_table = ams_id,
> +};
> +
> +static s32 ams_i2c_read(u8 reg)
> +{
> + return i2c_smbus_read_byte_data(ams_info.i2c_client, reg);
> +}
> +
> +static int ams_i2c_write(u8 reg, u8 value)
> +{
> + return i2c_smbus_write_byte_data(ams_info.i2c_client, reg, value);
> +}
> +
> +static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
> +{
> + s32 result;
> + int count = 3;
> +
> + ams_i2c_write(AMS_COMMAND, cmd);
> + msleep(5);
> +
> + while (count--) {
> + result = ams_i2c_read(AMS_COMMAND);
> + if (result == 0 || result & 0x80)
> + return 0;
> +
> + schedule_timeout_uninterruptible(HZ / 20);
> + }
> +
> + return -1;
> +}
> +
> +static void ams_i2c_set_irq(enum ams_irq reg, char enable)
> +{
> + if (reg & AMS_IRQ_FREEFALL) {
> + u8 val = ams_i2c_read(AMS_CTRLX);
> + if (enable)
> + val |= 0x80;
> + else
> + val &= ~0x80;
> + ams_i2c_write(AMS_CTRLX, val);
> + }
> +
> + if (reg & AMS_IRQ_SHOCK) {
> + u8 val = ams_i2c_read(AMS_CTRLY);
> + if (enable)
> + val |= 0x80;
> + else
> + val &= ~0x80;
> + ams_i2c_write(AMS_CTRLY, val);
> + }
> +
> + if (reg & AMS_IRQ_GLOBAL) {
> + u8 val = ams_i2c_read(AMS_CTRLZ);
> + if (enable)
> + val |= 0x80;
> + else
> + val &= ~0x80;
> + ams_i2c_write(AMS_CTRLZ, val);
> + }
> +}
> +
> +static void ams_i2c_clear_irq(enum ams_irq reg)
> +{
> + if (reg & AMS_IRQ_FREEFALL)
> + ams_i2c_write(AMS_FREEFALL, 0);
> +
> + if (reg & AMS_IRQ_SHOCK)
> + ams_i2c_write(AMS_SHOCK, 0);
> +}
> +
> +static u8 ams_i2c_get_vendor(void)
> +{
> + return ams_i2c_read(AMS_VENDOR);
> +}
> +
> +static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z)
> +{
> + *x = ams_i2c_read(AMS_DATAX);
> + *y = ams_i2c_read(AMS_DATAY);
> + *z = ams_i2c_read(AMS_DATAZ);
> +}
> +
> +static int ams_i2c_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + int vmaj, vmin;
> + int result;
> +
> + /* There can be only one */
> + if (unlikely(ams_info.has_device))
> + return -ENODEV;
> +
> + ams_info.i2c_client = client;
> +
> + if (ams_i2c_cmd(AMS_CMD_RESET)) {
> + printk(KERN_INFO "ams: Failed to reset the device\n");
> + return -ENODEV;
> + }
> +
> + if (ams_i2c_cmd(AMS_CMD_START)) {
> + printk(KERN_INFO "ams: Failed to start the device\n");
> + return -ENODEV;
> + }
> +
> + /* get version/vendor information */
> + ams_i2c_write(AMS_CTRL1, 0x02);
> + ams_i2c_write(AMS_CTRL2, 0x85);
> + ams_i2c_write(AMS_CTRL3, 0x01);
> +
> + ams_i2c_cmd(AMS_CMD_READMEM);
> +
> + vmaj = ams_i2c_read(AMS_DATA1);
> + vmin = ams_i2c_read(AMS_DATA2);
> + if (vmaj != 1 || vmin != 52) {
> + printk(KERN_INFO "ams: Incorrect device version (%d.%d)\n",
> + vmaj, vmin);
> + return -ENODEV;
> + }
> +
> + ams_i2c_cmd(AMS_CMD_VERSION);
> +
> + vmaj = ams_i2c_read(AMS_DATA1);
> + vmin = ams_i2c_read(AMS_DATA2);
> + if (vmaj != 0 || vmin != 1) {
> + printk(KERN_INFO "ams: Incorrect firmware version (%d.%d)\n",
> + vmaj, vmin);
> + return -ENODEV;
> + }
> +
> + /* Disable interrupts */
> + ams_i2c_set_irq(AMS_IRQ_ALL, 0);
> +
> + result = ams_sensor_attach();
> + if (result < 0)
> + return result;
> +
> + /* Set default values */
> + ams_i2c_write(AMS_SENSLOW, 0x15);
> + ams_i2c_write(AMS_SENSHIGH, 0x60);
> + ams_i2c_write(AMS_CTRLX, 0x08);
> + ams_i2c_write(AMS_CTRLY, 0x0F);
> + ams_i2c_write(AMS_CTRLZ, 0x4F);
> + ams_i2c_write(AMS_UNKNOWN1, 0x14);
> +
> + /* Clear interrupts */
> + ams_i2c_clear_irq(AMS_IRQ_ALL);
> +
> + ams_info.has_device = 1;
> +
> + /* Enable interrupts */
> + ams_i2c_set_irq(AMS_IRQ_ALL, 1);
> +
> + printk(KERN_INFO "ams: Found I2C based motion sensor\n");
> +
> + return 0;
> +}
> +
> +static int ams_i2c_remove(struct i2c_client *client)
> +{
> + if (ams_info.has_device) {
> + ams_sensor_detach();
> +
> + /* Disable interrupts */
> + ams_i2c_set_irq(AMS_IRQ_ALL, 0);
> +
> + /* Clear interrupts */
> + ams_i2c_clear_irq(AMS_IRQ_ALL);
> +
> + printk(KERN_INFO "ams: Unloading\n");
> +
> + ams_info.has_device = 0;
> + }
> +
> + return 0;
> +}
> +
> +static void ams_i2c_exit(void)
> +{
> + i2c_del_driver(&ams_i2c_driver);
> +}
> +
> +int __init ams_i2c_init(struct device_node *np)
> +{
> + int result;
> +
> + /* Set implementation stuff */
> + ams_info.of_node = np;
> + ams_info.exit = ams_i2c_exit;
> + ams_info.get_vendor = ams_i2c_get_vendor;
> + ams_info.get_xyz = ams_i2c_get_xyz;
> + ams_info.clear_irq = ams_i2c_clear_irq;
> + ams_info.bustype = BUS_I2C;
> +
> + result = i2c_add_driver(&ams_i2c_driver);
> +
> + return result;
> +}
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.36-rc6/drivers/macintosh/ams/ams-input.c 2010-08-02 00:11:14.000000000 +0200
> @@ -0,0 +1,157 @@
> +/*
> + * Apple Motion Sensor driver (joystick emulation)
> + *
> + * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
> + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +
> +#include "ams.h"
> +
> +static unsigned int joystick;
> +module_param(joystick, bool, S_IRUGO);
> +MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
> +
> +static unsigned int invert;
> +module_param(invert, bool, S_IWUSR | S_IRUGO);
> +MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
> +
> +static DEFINE_MUTEX(ams_input_mutex);
> +
> +static void ams_idev_poll(struct input_polled_dev *dev)
> +{
> + struct input_dev *idev = dev->input;
> + s8 x, y, z;
> +
> + mutex_lock(&ams_info.lock);
> +
> + ams_sensors(&x, &y, &z);
> +
> + x -= ams_info.xcalib;
> + y -= ams_info.ycalib;
> + z -= ams_info.zcalib;
> +
> + input_report_abs(idev, ABS_X, invert ? -x : x);
> + input_report_abs(idev, ABS_Y, invert ? -y : y);
> + input_report_abs(idev, ABS_Z, z);
> +
> + input_sync(idev);
> +
> + mutex_unlock(&ams_info.lock);
> +}
> +
> +/* Call with ams_info.lock held! */
> +static int ams_input_enable(void)
> +{
> + struct input_dev *input;
> + s8 x, y, z;
> + int error;
> +
> + ams_sensors(&x, &y, &z);
> + ams_info.xcalib = x;
> + ams_info.ycalib = y;
> + ams_info.zcalib = z;
> +
> + ams_info.idev = input_allocate_polled_device();
> + if (!ams_info.idev)
> + return -ENOMEM;
> +
> + ams_info.idev->poll = ams_idev_poll;
> + ams_info.idev->poll_interval = 25;
> +
> + input = ams_info.idev->input;
> + input->name = "Apple Motion Sensor";
> + input->id.bustype = ams_info.bustype;
> + input->id.vendor = 0;
> + input->dev.parent = &ams_info.of_dev->dev;
> +
> + input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
> + input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
> + input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
> +
> + set_bit(EV_ABS, input->evbit);
> + set_bit(EV_KEY, input->evbit);
> + set_bit(BTN_TOUCH, input->keybit);
> +
> + error = input_register_polled_device(ams_info.idev);
> + if (error) {
> + input_free_polled_device(ams_info.idev);
> + ams_info.idev = NULL;
> + return error;
> + }
> +
> + joystick = 1;
> +
> + return 0;
> +}
> +
> +static void ams_input_disable(void)
> +{
> + if (ams_info.idev) {
> + input_unregister_polled_device(ams_info.idev);
> + input_free_polled_device(ams_info.idev);
> + ams_info.idev = NULL;
> + }
> +
> + joystick = 0;
> +}
> +
> +static ssize_t ams_input_show_joystick(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + return sprintf(buf, "%d\n", joystick);
> +}
> +
> +static ssize_t ams_input_store_joystick(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t count)
> +{
> + unsigned long enable;
> + int error = 0;
> +
> + if (strict_strtoul(buf, 0, &enable) || enable > 1)
> + return -EINVAL;
> +
> + mutex_lock(&ams_input_mutex);
> +
> + if (enable != joystick) {
> + if (enable)
> + error = ams_input_enable();
> + else
> + ams_input_disable();
> + }
> +
> + mutex_unlock(&ams_input_mutex);
> +
> + return error ? error : count;
> +}
> +
> +static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
> + ams_input_show_joystick, ams_input_store_joystick);
> +
> +int ams_input_init(void)
> +{
> + if (joystick)
> + ams_input_enable();
> +
> + return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
> +}
> +
> +void ams_input_exit(void)
> +{
> + device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
> +
> + mutex_lock(&ams_input_mutex);
> + ams_input_disable();
> + mutex_unlock(&ams_input_mutex);
> +}
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.36-rc6/drivers/macintosh/ams/ams-pmu.c 2010-08-02 00:11:14.000000000 +0200
> @@ -0,0 +1,201 @@
> +/*
> + * Apple Motion Sensor driver (PMU variant)
> + *
> + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/adb.h>
> +#include <linux/pmu.h>
> +
> +#include "ams.h"
> +
> +/* Attitude */
> +#define AMS_X 0x00
> +#define AMS_Y 0x01
> +#define AMS_Z 0x02
> +
> +/* Not exactly known, maybe chip vendor */
> +#define AMS_VENDOR 0x03
> +
> +/* Freefall registers */
> +#define AMS_FF_CLEAR 0x04
> +#define AMS_FF_ENABLE 0x05
> +#define AMS_FF_LOW_LIMIT 0x06
> +#define AMS_FF_DEBOUNCE 0x07
> +
> +/* Shock registers */
> +#define AMS_SHOCK_CLEAR 0x08
> +#define AMS_SHOCK_ENABLE 0x09
> +#define AMS_SHOCK_HIGH_LIMIT 0x0a
> +#define AMS_SHOCK_DEBOUNCE 0x0b
> +
> +/* Global interrupt and power control register */
> +#define AMS_CONTROL 0x0c
> +
> +static u8 ams_pmu_cmd;
> +
> +static void ams_pmu_req_complete(struct adb_request *req)
> +{
> + complete((struct completion *)req->arg);
> +}
> +
> +/* Only call this function from task context */
> +static void ams_pmu_set_register(u8 reg, u8 value)
> +{
> + static struct adb_request req;
> + DECLARE_COMPLETION(req_complete);
> +
> + req.arg = &req_complete;
> + if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
> + return;
> +
> + wait_for_completion(&req_complete);
> +}
> +
> +/* Only call this function from task context */
> +static u8 ams_pmu_get_register(u8 reg)
> +{
> + static struct adb_request req;
> + DECLARE_COMPLETION(req_complete);
> +
> + req.arg = &req_complete;
> + if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
> + return 0;
> +
> + wait_for_completion(&req_complete);
> +
> + if (req.reply_len > 0)
> + return req.reply[0];
> + else
> + return 0;
> +}
> +
> +/* Enables or disables the specified interrupts */
> +static void ams_pmu_set_irq(enum ams_irq reg, char enable)
> +{
> + if (reg & AMS_IRQ_FREEFALL) {
> + u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
> + if (enable)
> + val |= 0x80;
> + else
> + val &= ~0x80;
> + ams_pmu_set_register(AMS_FF_ENABLE, val);
> + }
> +
> + if (reg & AMS_IRQ_SHOCK) {
> + u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
> + if (enable)
> + val |= 0x80;
> + else
> + val &= ~0x80;
> + ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
> + }
> +
> + if (reg & AMS_IRQ_GLOBAL) {
> + u8 val = ams_pmu_get_register(AMS_CONTROL);
> + if (enable)
> + val |= 0x80;
> + else
> + val &= ~0x80;
> + ams_pmu_set_register(AMS_CONTROL, val);
> + }
> +}
> +
> +static void ams_pmu_clear_irq(enum ams_irq reg)
> +{
> + if (reg & AMS_IRQ_FREEFALL)
> + ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
> +
> + if (reg & AMS_IRQ_SHOCK)
> + ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
> +}
> +
> +static u8 ams_pmu_get_vendor(void)
> +{
> + return ams_pmu_get_register(AMS_VENDOR);
> +}
> +
> +static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
> +{
> + *x = ams_pmu_get_register(AMS_X);
> + *y = ams_pmu_get_register(AMS_Y);
> + *z = ams_pmu_get_register(AMS_Z);
> +}
> +
> +static void ams_pmu_exit(void)
> +{
> + ams_sensor_detach();
> +
> + /* Disable interrupts */
> + ams_pmu_set_irq(AMS_IRQ_ALL, 0);
> +
> + /* Clear interrupts */
> + ams_pmu_clear_irq(AMS_IRQ_ALL);
> +
> + ams_info.has_device = 0;
> +
> + printk(KERN_INFO "ams: Unloading\n");
> +}
> +
> +int __init ams_pmu_init(struct device_node *np)
> +{
> + const u32 *prop;
> + int result;
> +
> + /* Set implementation stuff */
> + ams_info.of_node = np;
> + ams_info.exit = ams_pmu_exit;
> + ams_info.get_vendor = ams_pmu_get_vendor;
> + ams_info.get_xyz = ams_pmu_get_xyz;
> + ams_info.clear_irq = ams_pmu_clear_irq;
> + ams_info.bustype = BUS_HOST;
> +
> + /* Get PMU command, should be 0x4e, but we can never know */
> + prop = of_get_property(ams_info.of_node, "reg", NULL);
> + if (!prop)
> + return -ENODEV;
> +
> + ams_pmu_cmd = ((*prop) >> 8) & 0xff;
> +
> + /* Disable interrupts */
> + ams_pmu_set_irq(AMS_IRQ_ALL, 0);
> +
> + /* Clear interrupts */
> + ams_pmu_clear_irq(AMS_IRQ_ALL);
> +
> + result = ams_sensor_attach();
> + if (result < 0)
> + return result;
> +
> + /* Set default values */
> + ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
> + ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
> + ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
> +
> + ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
> + ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
> + ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
> +
> + ams_pmu_set_register(AMS_CONTROL, 0x4f);
> +
> + /* Clear interrupts */
> + ams_pmu_clear_irq(AMS_IRQ_ALL);
> +
> + ams_info.has_device = 1;
> +
> + /* Enable interrupts */
> + ams_pmu_set_irq(AMS_IRQ_ALL, 1);
> +
> + printk(KERN_INFO "ams: Found PMU based motion sensor\n");
> +
> + return 0;
> +}
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.36-rc6/drivers/macintosh/ams/ams.h 2010-09-21 11:07:14.000000000 +0200
> @@ -0,0 +1,70 @@
> +#include <linux/i2c.h>
> +#include <linux/input-polldev.h>
> +#include <linux/kthread.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <linux/of_device.h>
> +
> +enum ams_irq {
> + AMS_IRQ_FREEFALL = 0x01,
> + AMS_IRQ_SHOCK = 0x02,
> + AMS_IRQ_GLOBAL = 0x04,
> + AMS_IRQ_ALL =
> + AMS_IRQ_FREEFALL |
> + AMS_IRQ_SHOCK |
> + AMS_IRQ_GLOBAL,
> +};
> +
> +struct ams {
> + /* Locks */
> + spinlock_t irq_lock;
> + struct mutex lock;
> +
> + /* General properties */
> + struct device_node *of_node;
> + struct platform_device *of_dev;
> + char has_device;
> + char vflag;
> + u32 orient1;
> + u32 orient2;
> +
> + /* Interrupt worker */
> + struct work_struct worker;
> + u8 worker_irqs;
> +
> + /* Implementation
> + *
> + * Only call these functions with the main lock held.
> + */
> + void (*exit)(void);
> +
> + void (*get_xyz)(s8 *x, s8 *y, s8 *z);
> + u8 (*get_vendor)(void);
> +
> + void (*clear_irq)(enum ams_irq reg);
> +
> +#ifdef CONFIG_SENSORS_AMS_I2C
> + /* I2C properties */
> + struct i2c_client *i2c_client;
> +#endif
> +
> + /* Joystick emulation */
> + struct input_polled_dev *idev;
> + __u16 bustype;
> +
> + /* calibrated null values */
> + int xcalib, ycalib, zcalib;
> +};
> +
> +extern struct ams ams_info;
> +
> +extern void ams_sensors(s8 *x, s8 *y, s8 *z);
> +extern int ams_sensor_attach(void);
> +extern void ams_sensor_detach(void);
> +
> +extern int ams_pmu_init(struct device_node *np);
> +extern int ams_i2c_init(struct device_node *np);
> +
> +extern int ams_input_init(void);
> +extern void ams_input_exit(void);
> --- linux-2.6.36-rc6.orig/MAINTAINERS 2010-10-05 10:45:16.000000000 +0200
> +++ linux-2.6.36-rc6/MAINTAINERS 2010-10-05 11:51:21.000000000 +0200
> @@ -445,7 +445,7 @@ AMS (Apple Motion Sensor) DRIVER
> M: Stelian Pop <stelian@popies.net>
> M: Michael Hanselmann <linux-kernel@hansmi.ch>
> S: Supported
> -F: drivers/hwmon/ams/
> +F: drivers/macintosh/ams/
>
> AMSO1100 RNIC DRIVER
> M: Tom Tucker <tom@opengridcomputing.com>
> --- linux-2.6.36-rc6.orig/drivers/hwmon/Kconfig 2010-10-05 10:45:16.000000000 +0200
> +++ linux-2.6.36-rc6/drivers/hwmon/Kconfig 2010-10-05 11:42:38.000000000 +0200
> @@ -249,32 +249,6 @@ config SENSORS_K10TEMP
> This driver can also be built as a module. If so, the module
> will be called k10temp.
>
> -config SENSORS_AMS
> - tristate "Apple Motion Sensor driver"
> - depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
> - select INPUT_POLLDEV
> - help
> - Support for the motion sensor included in PowerBooks. Includes
> - implementations for PMU and I2C.
> -
> - This driver can also be built as a module. If so, the module
> - will be called ams.
> -
> -config SENSORS_AMS_PMU
> - bool "PMU variant"
> - depends on SENSORS_AMS && ADB_PMU
> - default y
> - help
> - PMU variant of motion sensor, found in late 2005 PowerBooks.
> -
> -config SENSORS_AMS_I2C
> - bool "I2C variant"
> - depends on SENSORS_AMS && I2C
> - default y
> - help
> - I2C variant of motion sensor, found in early 2005 PowerBooks and
> - iBooks.
> -
> config SENSORS_ASB100
> tristate "Asus ASB100 Bach"
> depends on X86 && I2C && EXPERIMENTAL
> --- linux-2.6.36-rc6.orig/drivers/hwmon/Makefile 2010-10-05 10:45:16.000000000 +0200
> +++ linux-2.6.36-rc6/drivers/hwmon/Makefile 2010-10-05 11:41:34.000000000 +0200
> @@ -36,7 +36,6 @@ obj-$(CONFIG_SENSORS_ADT7462) += adt7462
> obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
> obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
> obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
> -obj-$(CONFIG_SENSORS_AMS) += ams/
> obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
> obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
> obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
> --- linux-2.6.36-rc6.orig/drivers/macintosh/Kconfig 2010-08-02 00:11:14.000000000 +0200
> +++ linux-2.6.36-rc6/drivers/macintosh/Kconfig 2010-10-05 11:42:49.000000000 +0200
> @@ -256,4 +256,30 @@ config PMAC_RACKMETER
> This driver provides some support to control the front panel
> blue LEDs "vu-meter" of the XServer macs.
>
> +config SENSORS_AMS
> + tristate "Apple Motion Sensor driver"
> + depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
> + select INPUT_POLLDEV
> + help
> + Support for the motion sensor included in PowerBooks. Includes
> + implementations for PMU and I2C.
> +
> + This driver can also be built as a module. If so, the module
> + will be called ams.
> +
> +config SENSORS_AMS_PMU
> + bool "PMU variant"
> + depends on SENSORS_AMS && ADB_PMU
> + default y
> + help
> + PMU variant of motion sensor, found in late 2005 PowerBooks.
> +
> +config SENSORS_AMS_I2C
> + bool "I2C variant"
> + depends on SENSORS_AMS && I2C
> + default y
> + help
> + I2C variant of motion sensor, found in early 2005 PowerBooks and
> + iBooks.
> +
> endif # MACINTOSH_DRIVERS
> --- linux-2.6.36-rc6.orig/drivers/macintosh/Makefile 2010-08-02 00:11:14.000000000 +0200
> +++ linux-2.6.36-rc6/drivers/macintosh/Makefile 2010-10-05 11:42:05.000000000 +0200
> @@ -48,3 +48,5 @@ obj-$(CONFIG_WINDFARM_PM121) += windfarm
> windfarm_max6690_sensor.o \
> windfarm_lm75_sensor.o windfarm_pid.o
> obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o
> +
> +obj-$(CONFIG_SENSORS_AMS) += ams/
>
>
^ permalink raw reply
* Re: [PATCH 1/2] of: Add support for linking device tree blobs into vmlinux
From: Grant Likely @ 2010-11-16 5:17 UTC (permalink / raw)
To: Dirk Brandewie; +Cc: sodaville, devicetree-discuss, arjan, linuxppc-dev
In-Reply-To: <4CE21163.2070806@gmail.com>
On Mon, Nov 15, 2010 at 10:06 PM, Dirk Brandewie
<dirk.brandewie@gmail.com> wrote:
> On 11/15/2010 08:41 PM, Grant Likely wrote:
>>
>> On Mon, Nov 15, 2010 at 08:01:20PM -0800, dirk.brandewie@gmail.com wrote=
:
>>>
>>> From: Dirk Brandewie<dirk.brandewie@gmail.com>
>>>
>>> This patch adds support for linking device tree blobs into
>>> vmlinux. The device tree blobs are placed in the init.data
>>> section.
>>>
>>> Signed-off-by: Dirk Brandewie<dirk.brandewie@gmail.com>
>>> ---
>>> =A0include/asm-generic/vmlinux.lds.h | =A0 19 +++++++++++++++++--
>>> =A0scripts/Makefile.lib =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 17 +++++++++++=
++++++
>>> =A02 files changed, 34 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/include/asm-generic/vmlinux.lds.h
>>> b/include/asm-generic/vmlinux.lds.h
>>> index bd69d79..ea671e7 100644
>>> --- a/include/asm-generic/vmlinux.lds.h
>>> +++ b/include/asm-generic/vmlinux.lds.h
>>> @@ -67,7 +67,14 @@
>>> =A0 * Align to a 32 byte boundary equal to the
>>> =A0 * alignment gcc 4.5 uses for a struct
>>> =A0 */
>>> -#define STRUCT_ALIGN() . =3D ALIGN(32)
>>> +#define STRUCT_ALIGNMENT 32
>>> +#define STRUCT_ALIGN() . =3D ALIGN(STRUCT_ALIGNMENT)
>>> +
>>> +/* Device tree blobs linked into the kernel need to have proper
>>> + * structure alignment to be parsed by the flat device tree library
>>> + * used in early boot
>>> +*/
>>> +#define DTB_ALIGNMENT STRUCT_ALIGNMENT
>>>
>>> =A0/* The actual configuration determine if the init/exit sections
>>> =A0 * are handled as text/data or they can be discarded (which
>>> @@ -146,6 +153,13 @@
>>> =A0#define TRACE_SYSCALLS()
>>> =A0#endif
>>>
>>> +
>>> +#define KERNEL_DTB() =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
>>> + =A0 =A0 =A0 . =3D ALIGN(DTB_ALIGNMENT); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
>>> + =A0 =A0 =A0 VMLINUX_SYMBOL(__dtb_start) =3D .; =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
>>> + =A0 =A0 =A0 *(.dtb.init.rodata) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
>>> + =A0 =A0 =A0 VMLINUX_SYMBOL(__dtb_end) =3D .;
>>> +
>>> =A0/* .data section */
>>> =A0#define DATA_DATA =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
>>> =A0 =A0 =A0 =A0*(.data) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
>>> @@ -468,7 +482,8 @@
>>> =A0 =A0 =A0 =A0MCOUNT_REC() =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
>>> =A0 =A0 =A0 =A0DEV_DISCARD(init.rodata) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
>>> =A0 =A0 =A0 =A0CPU_DISCARD(init.rodata) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
>>> - =A0 =A0 =A0 MEM_DISCARD(init.rodata)
>>> + =A0 =A0 =A0 MEM_DISCARD(init.rodata) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
>>> + =A0 =A0 =A0 KERNEL_DTB()
>>>
>>> =A0#define INIT_TEXT =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
>>> =A0 =A0 =A0 =A0*(.init.text) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
>>> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
>>> index 4c72c11..a8a4774 100644
>>> --- a/scripts/Makefile.lib
>>> +++ b/scripts/Makefile.lib
>>> @@ -200,6 +200,23 @@ quiet_cmd_gzip =3D GZIP =A0 =A0$@
>>> =A0cmd_gzip =3D (cat $(filter-out FORCE,$^) | gzip -f -9> =A0$@) || \
>>> =A0 =A0 =A0 =A0(rm -f $@ ; false)
>>>
>>> +# DTC
>>> +#
>>> =A0--------------------------------------------------------------------=
-------
>>> +$(obj)/%.dtb.S: $(obj)/%.dtb FORCE
>>> + =A0 =A0 =A0 @echo '#include<asm-generic/vmlinux.lds.h>'> =A0$@
>>> + =A0 =A0 =A0 @echo '.section .dtb.init.rodata,"a"'>> =A0$@
>>> + =A0 =A0 =A0 @echo '.balign DTB_ALIGNMENT'>> =A0$@
>>> + =A0 =A0 =A0 @echo '.global __dtb_$(*F)_begin'>> =A0$@
>>> + =A0 =A0 =A0 @echo '__dtb_$(*F)_begin:'>> =A0$@
>>> + =A0 =A0 =A0 @echo '.incbin "$<" '>> =A0$@
>>> + =A0 =A0 =A0 @echo '__dtb_$(*F)_end:'>> =A0$@
>>> + =A0 =A0 =A0 @echo '.global __dtb_$(*F)_end'>> =A0$@
>>> + =A0 =A0 =A0 @echo '.balign DTB_ALIGNMENT'>> =A0$@
>>> +
>>> +DTC =3D $(objtree)/scripts/dtc/dtc
>>> +
>>> +quiet_cmd_dtc =3D DTC =A0 =A0$@
>>> + =A0 =A0 =A0cmd_dtc =3D $(DTC) -O dtb -o $(obj)/$*.dtb -b 0 =A0$(src)/=
$*.dts
>>
>> Missing the %.dtb: %.dts rule, but otherwise looks okay. =A0You will
>> need to make sure this doesn't break powerpc or microblaze when the
>> dts->dtb rule is added.
>>
> I have the rule
> =A0$(obj)/%.dtb: $(src)/%.dts
> =A0 =A0 =A0 =A0 =A0$(call if_changed,dtc)
> in the arch/x86/kernel/Makefile to prevent this sneaking into other other
> architectures.
This rule looks correct. PowerPC and Microblaze need to be modified
to use it. It should not be hard to do, give it a try. Worst case,
your first attempt is wrong and the rest of us fix it up. :-)
Hint: PowerPC currently puts the .dtb file in a different directory
from the source .dts file. It doesn't need to do it that way.
arch/powerpc/boot/Makefile will need to be modified.
g.
>
> I need some more skilled in kbuild to help craft the more generic rule so=
we
> can have the dts files anywhere in the arch/<*>/ directory structure and =
be
> able to find the correct dts files.
>
> --Dirk
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 1/2] of: Add support for linking device tree blobs into vmlinux
From: Dirk Brandewie @ 2010-11-16 5:28 UTC (permalink / raw)
To: Grant Likely; +Cc: sodaville, devicetree-discuss, arjan, linuxppc-dev
In-Reply-To: <AANLkTi=G1TwfOHBVB2wpZHpafw_KB7S7yhj6syP339e1@mail.gmail.com>
On 11/15/2010 09:17 PM, Grant Likely wrote:
> On Mon, Nov 15, 2010 at 10:06 PM, Dirk Brandewie
> <dirk.brandewie@gmail.com> wrote:
>> On 11/15/2010 08:41 PM, Grant Likely wrote:
>>>
>>> On Mon, Nov 15, 2010 at 08:01:20PM -0800, dirk.brandewie@gmail.com wrote:
>>>>
>>>> From: Dirk Brandewie<dirk.brandewie@gmail.com>
>>>>
>>>> This patch adds support for linking device tree blobs into
>>>> vmlinux. The device tree blobs are placed in the init.data
>>>> section.
>>>>
>>>> Signed-off-by: Dirk Brandewie<dirk.brandewie@gmail.com>
>>>> ---
>>>> include/asm-generic/vmlinux.lds.h | 19 +++++++++++++++++--
>>>> scripts/Makefile.lib | 17 +++++++++++++++++
>>>> 2 files changed, 34 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/include/asm-generic/vmlinux.lds.h
>>>> b/include/asm-generic/vmlinux.lds.h
>>>> index bd69d79..ea671e7 100644
>>>> --- a/include/asm-generic/vmlinux.lds.h
>>>> +++ b/include/asm-generic/vmlinux.lds.h
>>>> @@ -67,7 +67,14 @@
>>>> * Align to a 32 byte boundary equal to the
>>>> * alignment gcc 4.5 uses for a struct
>>>> */
>>>> -#define STRUCT_ALIGN() . = ALIGN(32)
>>>> +#define STRUCT_ALIGNMENT 32
>>>> +#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
>>>> +
>>>> +/* Device tree blobs linked into the kernel need to have proper
>>>> + * structure alignment to be parsed by the flat device tree library
>>>> + * used in early boot
>>>> +*/
>>>> +#define DTB_ALIGNMENT STRUCT_ALIGNMENT
>>>>
>>>> /* The actual configuration determine if the init/exit sections
>>>> * are handled as text/data or they can be discarded (which
>>>> @@ -146,6 +153,13 @@
>>>> #define TRACE_SYSCALLS()
>>>> #endif
>>>>
>>>> +
>>>> +#define KERNEL_DTB() \
>>>> + . = ALIGN(DTB_ALIGNMENT); \
>>>> + VMLINUX_SYMBOL(__dtb_start) = .; \
>>>> + *(.dtb.init.rodata) \
>>>> + VMLINUX_SYMBOL(__dtb_end) = .;
>>>> +
>>>> /* .data section */
>>>> #define DATA_DATA \
>>>> *(.data) \
>>>> @@ -468,7 +482,8 @@
>>>> MCOUNT_REC() \
>>>> DEV_DISCARD(init.rodata) \
>>>> CPU_DISCARD(init.rodata) \
>>>> - MEM_DISCARD(init.rodata)
>>>> + MEM_DISCARD(init.rodata) \
>>>> + KERNEL_DTB()
>>>>
>>>> #define INIT_TEXT \
>>>> *(.init.text) \
>>>> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
>>>> index 4c72c11..a8a4774 100644
>>>> --- a/scripts/Makefile.lib
>>>> +++ b/scripts/Makefile.lib
>>>> @@ -200,6 +200,23 @@ quiet_cmd_gzip = GZIP $@
>>>> cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9> $@) || \
>>>> (rm -f $@ ; false)
>>>>
>>>> +# DTC
>>>> +#
>>>> ---------------------------------------------------------------------------
>>>> +$(obj)/%.dtb.S: $(obj)/%.dtb FORCE
>>>> + @echo '#include<asm-generic/vmlinux.lds.h>'> $@
>>>> + @echo '.section .dtb.init.rodata,"a"'>> $@
>>>> + @echo '.balign DTB_ALIGNMENT'>> $@
>>>> + @echo '.global __dtb_$(*F)_begin'>> $@
>>>> + @echo '__dtb_$(*F)_begin:'>> $@
>>>> + @echo '.incbin "$<" '>> $@
>>>> + @echo '__dtb_$(*F)_end:'>> $@
>>>> + @echo '.global __dtb_$(*F)_end'>> $@
>>>> + @echo '.balign DTB_ALIGNMENT'>> $@
>>>> +
>>>> +DTC = $(objtree)/scripts/dtc/dtc
>>>> +
>>>> +quiet_cmd_dtc = DTC $@
>>>> + cmd_dtc = $(DTC) -O dtb -o $(obj)/$*.dtb -b 0 $(src)/$*.dts
>>>
>>> Missing the %.dtb: %.dts rule, but otherwise looks okay. You will
>>> need to make sure this doesn't break powerpc or microblaze when the
>>> dts->dtb rule is added.
>>>
>> I have the rule
>> $(obj)/%.dtb: $(src)/%.dts
>> $(call if_changed,dtc)
>> in the arch/x86/kernel/Makefile to prevent this sneaking into other other
>> architectures.
>
> This rule looks correct. PowerPC and Microblaze need to be modified
> to use it. It should not be hard to do, give it a try. Worst case,
> your first attempt is wrong and the rest of us fix it up. :-)
>
> Hint: PowerPC currently puts the .dtb file in a different directory
> from the source .dts file. It doesn't need to do it that way.
> arch/powerpc/boot/Makefile will need to be modified.
>
I will give it a shot. The only real difference except for the directory
structures is powerpc and microblaze add padding to the dtb with the -p 1024
command line argument to dtc. Is the padding needed when the blob are linked
into vmlinux proper?
--Dirk
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox