Subject: kern/36745: Add spdmem device for I2C
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <paul@whooppee.com>
List: netbsd-bugs
Date: 08/07/2007 13:00:01
>Number:         36745
>Category:       kern
>Synopsis:       Add spdmem device for I2C
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 07 13:00:01 +0000 2007
>Originator:     Paul Goyette
>Release:        NetBSD 4.99.26 sources as of 2007-08-01 12:42:27 UTC
>Organization:
>Environment:
System: NetBSD quicky.whooppee.com 4.99.26 NetBSD 4.99.26 (QUICKY (ASUS A8N5X) 2007-08-01 12:42:27 UTC) #185: Wed Aug 1 06:09:48 PDT 2007 paul@quicky.whooppee.com:/usr/obj/objdir/amd64/sys/arch/amd64/compile/QUICKY amd64
Architecture: x86_64
Machine: amd64
>Description:
	Add spdmem device for I2C busses.  Driver doesn't do much, other
	than identify the type of memory.
>How-To-Repeat:
>Fix:
Code originally provided by Nicolas Joly...

Index: i2c/files.i2c
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/files.i2c,v
retrieving revision 1.14
diff -u -p -r1.14 files.i2c
--- i2c/files.i2c	17 Jan 2007 23:33:23 -0000	1.14
+++ i2c/files.i2c	7 Aug 2007 11:47:03 -0000
@@ -106,3 +106,8 @@ file	dev/i2c/pic16lc.c		pic16lc needs-fl
 device	xbseeprom
 attach	xbseeprom at iic
 file	dev/i2c/xbseeprom.c		xbseeprom
+
+# Memory Serial Presence Detect
+device	spdmem
+attach	spdmem at iic
+file	dev/i2c/spdmem.c		spdmem



/* $NetBSD$ */

/*
 * Copyright (c) 2007 Nicolas Joly
+ * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");

#include <sys/param.h>
#include <sys/device.h>

#include <dev/i2c/i2cvar.h>

#define SPDMEM_MEMTYPE		0x02
#define SPDMEM_MEMTYPE_EDO		0x02
#define SPDMEM_MEMTYPE_SDRAM		0x04
#define SPDMEM_MEMTYPE_DDRSDRAM		0x07
#define SPDMEM_MEMTYPE_DDR2SDRAM	0x08

struct spdmem_softc {
	struct device	sc_dev;

	i2c_tag_t	sc_tag;
	i2c_addr_t	sc_addr;
};

static int spdmem_match(struct device *, struct cfdata *, void *);
static void spdmem_attach(struct device *, struct device *, void *);

static uint8_t spdmem_read(struct spdmem_softc *, uint8_t);

CFATTACH_DECL(spdmem, sizeof(struct spdmem_softc),
    spdmem_match, spdmem_attach, NULL, NULL);

static int
spdmem_match(struct device *parent, struct cfdata *match, void *aux)
{
	struct i2c_attach_args *ia = aux;
	struct spdmem_softc sc;
	int cksum = 0;
	uint8_t i, val;

	if (ia->ia_addr < 0x50)
		return 0;

	sc.sc_tag = ia->ia_tag;
	sc.sc_addr = ia->ia_addr;

	for (i = 0; i < 63; i++)
		cksum += spdmem_read(&sc, i);
	val = spdmem_read(&sc, 63);
	if (cksum == 0 || (cksum & 0xff) != val)
		return 0;

	return 1;
}

static void
spdmem_attach(struct device *parent, struct device *self, void *aux)
{
	struct spdmem_softc *sc = device_private(self);
	struct i2c_attach_args *ia = aux;
	uint8_t val;
	const char *type;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;

	val = spdmem_read(sc, SPDMEM_MEMTYPE);
	switch (val) {
	case SPDMEM_MEMTYPE_EDO:
		type = "EDO";
		break;
	case SPDMEM_MEMTYPE_SDRAM:
		type = "SDRAM";
		break;
	case SPDMEM_MEMTYPE_DDRSDRAM:
		type = "DDR SDRAM";
		break;
	case SPDMEM_MEMTYPE_DDR2SDRAM:
		type = "DDR2 SDRAM";
		break;
	default:
		aprint_error(": unknown (0x%02x) memory type\n", val);
		return;
	}

	aprint_normal(": %s memory module\n", type);

	return;
}

static uint8_t
spdmem_read(struct spdmem_softc *sc, uint8_t reg)
{
	uint8_t val;

	iic_acquire_bus(sc->sc_tag,0);
	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg, 1,
		 &val, 1, 0);
	iic_release_bus(sc->sc_tag, 0);

	return val;
}