All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tolunay Orkun <listmember@orkun.us>
To: Sam Song <samlinuxppc@yahoo.com.cn>
Cc: linuxppc-embedded@ozlabs.org
Subject: Re: Available user-level tool for I2C device?
Date: Thu, 29 Sep 2005 13:59:26 -0500	[thread overview]
Message-ID: <433C398E.30408@orkun.us> (raw)
In-Reply-To: <20050929123535.66570.qmail@web15803.mail.cnb.yahoo.com>

[-- Attachment #1: Type: text/plain, Size: 530 bytes --]

Sam,

Sam Song wrote:
> Hi all,
> 
> I'd like to ask whether there is user-level utility
> for I2C device registers access like lspci/setpci for
> PCI device?
> 
> I have a RTC chip DS1337 on a 8248 target. It can
> work right in u-boot and linux. If no similar utility,
> I will switch to change hwclock.c in busybox to make
> it. Any idea?
> 
> Thanks in advance,
> 
> Sam

I've a hwclock.c implementation for DS1307/DS1338. I do not know how
close DS1337 was but it should not be too difficult to adapt.

Best regards,
Tolunay

[-- Attachment #2: hwclock_ds1307.c --]
[-- Type: text/x-csrc, Size: 6803 bytes --]

/*
 * Mini hwclock implementation suitable for DS1307/DS1338 RTC chips
 *
 * Copyright (C) 2004 NextIO Inc. - Tolunay Orkun <torkun@nextio.com>
 *
 * Based on GPL licensed code from Busybox and U-boot projects
 *
 * 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 <sys/ioctl.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <stdio.h>
#include <libgen.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define DS1307_ADDR	0x68

struct i2c_ioctl_rdwr_data {
	struct i2c_msg *msgs;
	int nmsgs;
};

int i2c_xfer(int addr, char *wbuf, int wcount, char *rbuf, int rcount)
{
	int fd, i;
	int val, nmsgs;
	struct i2c_msg msg[2];
	struct i2c_ioctl_rdwr_data ioctl_rdwr_data;

	memset(msg, 0, sizeof(msg));
	memset(&ioctl_rdwr_data, 0, sizeof(ioctl_rdwr_data));

	nmsgs = 0;
	if (wcount > 0) {
		msg[nmsgs].addr  = addr;
		msg[nmsgs].flags = 0;
		msg[nmsgs].len   = wcount;
		msg[nmsgs].buf   = wbuf;
		nmsgs++;
	}

	if (rcount > 0) {
		msg[nmsgs].addr  = addr;
		msg[nmsgs].flags = I2C_M_RD;
		msg[nmsgs].len   = rcount;
		msg[nmsgs].buf   = rbuf;
		nmsgs++;
	}

	ioctl_rdwr_data.msgs = msg;
	ioctl_rdwr_data.nmsgs = nmsgs;

#ifdef DEBUG
	if (wcount > 0) {
		printf("Writing i2c...\n");
		printf("Addr : %3d (0x%02x)\n", addr, addr);
		printf("Count: %3d (0x%02x)\n", wcount, wcount);
		printf("Data :\n");
		for (i = 0; i < wcount; i++) {
			val = wbuf[i];
			printf("%3d (0x%02x) = %3d (0x%02x)\n", i, i, val, val);
		}
		printf("\n");
	}

	if (rcount > 0) {
		printf("Reading i2c...\n");
		printf("Addr : %3d (0x%02x)\n", addr, addr);
		printf("Count: %3d (0x%02x)\n", rcount, rcount);
	}
#endif

	fd = open("/dev/i2c0", O_RDWR);
	if (fd < 0) {
		fd = open("/dev/i2c/0", O_RDWR);
		if (fd < 0) {
			printf("Can't open i2c\n");
			return 1;
		}
	}

	if (ioctl(fd, I2C_RDWR, &ioctl_rdwr_data) < 0) {
		printf("I2C I/O Error\n");
		close(fd);
		return 2;
	}

#ifdef DEBUG
	if (rcount > 0) {
		printf("Data :\n");
		for (i = 0; i < rcount; i++) {
			val = rbuf[i];
			printf("%3d (0x%02x) = %3d (0x%02x)\n", i, i, val, val);
		}
		printf("\n");
	}
#endif
	
	close(fd);
	return 0;
}

unsigned int bcd2bin(unsigned char n)
{
	return ((((n >> 4) & 0x0f) * 10) + (n & 0x0f));
}

unsigned char bin2bcd(unsigned int n)
{
	return (((n / 10) << 4) | (n % 10));
}

time_t read_rtc(int utc)
{
	char reg = 0; /* register start address for transfer */
	char buf[8];
	struct tm tm;
	char *oldtz = NULL;
	time_t t = 0;

	if (i2c_xfer(DS1307_ADDR, &reg, sizeof(reg), buf, sizeof(buf)) != 0)
		return -1;

	memset(&tm, 0, sizeof(struct tm));
	tm.tm_sec  = bcd2bin(buf[0] & 0x7f);
	tm.tm_min  = bcd2bin(buf[1] & 0x7f);
	tm.tm_hour = bcd2bin(buf[2] & 0x3f);
	tm.tm_wday = bcd2bin(buf[3] & 0x07) - 1;
	tm.tm_mday = bcd2bin(buf[4] & 0x3f);
	tm.tm_mon  = bcd2bin(buf[5] & 0x1f) - 1;
	tm.tm_year = bcd2bin(buf[6]) + 100;
	tm.tm_isdst = -1; /* unknown */

	if (utc) {
		oldtz = getenv("TZ");
		setenv("TZ", "UTC 0", 1);
		tzset();
	}

	t = mktime(&tm);

	if (utc) {
		if (oldtz)
			setenv("TZ", oldtz, 1);
		else
			unsetenv("TZ");
		tzset();
	}

	return t;
}

int write_rtc(time_t t, int utc)
{
	char buf[8];
	struct tm tm;

	tm = *(utc ? gmtime(&t) : localtime(&t));

	buf[0] = 0; /* register start address for transfer */
	buf[1] = bin2bcd(tm.tm_sec);
	buf[2] = bin2bcd(tm.tm_min);
	buf[3] = bin2bcd(tm.tm_hour);
	buf[4] = bin2bcd(tm.tm_wday + 1);
	buf[5] = bin2bcd(tm.tm_mday);
	buf[6] = bin2bcd(tm.tm_mon + 1);
	buf[7] = bin2bcd(tm.tm_year - 100);

	if (i2c_xfer(DS1307_ADDR, buf, sizeof(buf), NULL, 0) != 0)
		return -1;

	return 0;
}

int show_clock(int utc)
{
	time_t t;
	char   buffer[64];
	char   *p;
	int    len;

	buffer[0] = '\0';
	t = read_rtc(utc);
	p = ctime(&t);
	if (p) {
		len = strlen(p) - 1; /* strip newline */
		if (len >= sizeof(buffer))
			len = sizeof(buffer) - 1;
		memcpy(buffer, p, len);
		buffer[len] = '\0';
	}

	printf("%s 0.000000 seconds\n", buffer);
	return 0;
}

int to_sys_clock(int utc)
{
	struct timeval tv;

	memset(&tv, 0, sizeof(tv));
	tv.tv_sec = read_rtc(utc);
	return settimeofday(&tv, NULL);
}

int from_sys_clock(int utc)
{
	struct timeval tv;

	memset(&tv, 0, sizeof(tv));
	gettimeofday(&tv, NULL);
	return write_rtc(tv.tv_sec, utc); 
}

void show_usage(char *progname)
{
	char buf[64];

	strncpy(buf, progname, sizeof(buf));
	buf[sizeof(buf) - 1] = '\0';
	basename(buf);

	printf("%s - query and set the hardware clock (DS1307/1338 RTC)\n\n", buf);
	printf("Usage: %s [options...]\n\n", buf);
	printf("Options:\n");
	printf("\t-r, --show\tread hardware clock and print result\n");
	printf("\t-s, --hctosys\tset the system time from the hardware clock\n");
	printf("\t-w, --systohc\tset the hardware clock to the current system time\n\n");
	printf("\t-u, --utc\tthe hardware clock is kept in universal time\n");
	printf("\t-l, --localtime\tthe hardware clock is kept in local time\n\n");
	exit(-1);
}

int main(int argc, char *argv[])
{
	int  opt_help = 0;
	int  opt_localtime = 0;
	int  opt_utc = 0;
	int  func_show = 0;
	int  func_hctosys = 0;
	int  func_systohc = 0;
	int  func_count;
	int  utc;
	int  c;

	static struct option long_options[] = {
		{ "show",	0, 0, 'r' },
		{ "hctosys",	0, 0, 's' },
		{ "systohc",	0, 0, 'w' },
		{ "localtime",	0, 0, 'l' },
		{ "utc",	0, 0, 'u' },
		{ "help",	0, 0, '?' },
		{ 0,		0, 0, 0   }
	};
	int opt_idx = 0;

	while (1) {
		c = getopt_long(argc, argv, "rswlu?h", long_options, &opt_idx);	
		if (c == -1)
			break;

		switch (c) {
			case 'r':
				func_show = 1;
				break;
			case 's':
				func_hctosys = 1;
				break;
			case 'w':
				func_systohc = 1;
				break;
			case 'l':
				opt_localtime = 1;
				break;
			case 'u':
				opt_utc = 1;
				break;
			default:
				opt_help = 1;
				break;
		}
	}

	func_count = func_show + func_hctosys + func_systohc;
	if (func_count > 1)
		show_usage(argv[0]);
	
	if (opt_localtime && opt_utc)
		show_usage(argv[0]);

	if (opt_help)
		show_usage(argv[0]);

	if (func_hctosys)
		return to_sys_clock(opt_utc);
	else if (func_systohc)
		return from_sys_clock(opt_utc);
	else
		return show_clock(opt_utc);
	
	return 0;
}

/* ex: set sw=4 ts=4: */

  parent reply	other threads:[~2005-09-29 18:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-29 12:35 Available user-level tool for I2C device? Sam Song
2005-09-29 16:57 ` Eugene Surovegin
2005-10-01  3:50   ` Sam Song
2005-09-29 18:59 ` Tolunay Orkun [this message]
2005-10-01  3:58   ` Sam Song
2005-10-02 13:58     ` Yuli Barcohen
2005-10-05  3:33       ` Sam Song

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=433C398E.30408@orkun.us \
    --to=listmember@orkun.us \
    --cc=linuxppc-embedded@ozlabs.org \
    --cc=samlinuxppc@yahoo.com.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.