linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Harald Welte <laforge@gnumonks.org>
To: linuxppc-dev@lists.linuxppc.org
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Subject: Re: [PATCH] ugly hack to make therm_pm72 work on XServe G5
Date: Fri, 6 Aug 2004 10:04:06 +0200	[thread overview]
Message-ID: <20040806080406.GB11638@sunbeam2> (raw)
In-Reply-To: <20040805114348.GD7112@sunbeam2>

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

I actually forgot that small userspace program ;)

It is a total ripoff of the kernel driver and was implemented because
it's easier to play with i2c from userspace during development.

benh:  Any reason why you implemented your own byte+word read/write
routines?  Apparently the i2c_smbus routines work quite fine, even from
userspace...

--
- Harald Welte <laforge@gnumonks.org>               http://www.gnumonks.org/
============================================================================
Programming is like sex: One mistake and you have to support it your lifetime

[-- Attachment #2: rackmac-fans.c --]
[-- Type: text/x-csrc, Size: 4722 bytes --]

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <linux/i2c-dev.h>

static int fd;

#ifdef RAW_I2C
static int fan_read_reg(int reg, unsigned char *buf, int nb)
{
	int tries, nr, nw;

	buf[0] = reg;
	tries = 0;
	for (;;) {
		nw = write(fd, buf, 1);
		if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
			break;
		usleep(10);
		++tries;
	}
	if (nw < 0) {
		fprintf(stderr, "Failure writing address to FCU: %d\n", nw);
		return -EIO;
	}
	tries = 0;
	for (;;) {
		nr = read(fd, buf, nb);
		if (nr > 0 || (nr < 0 && nr != ENODEV) || tries >= 100)
			break;
		usleep(10);
		++tries;
	}
	if (nr <= 0)
		fprintf(stderr, "Failure reading data from FCU: %d\n", nw);
	return nr;
}

static int fan_write_reg(int reg, const unsigned char *ptr, int nb)
{
	int tries, nw;
	unsigned char buf[16];

	buf[0] = reg;
	memcpy(buf+1, ptr, nb);
	++nb;
	tries = 0;

	for (;;) {
		nw = write(fd, buf, nb);
		if (nw > 0 || (nw < 0 && nw != EIO) || tries >= 100)
			break;
		usleep(1);
		++tries;
	}
	if (nw < 0)
		fprintf(stderr, "Failure writing to FCU: %d", nw);
	return nw;
}
#else
static int fan_read_reg(int reg, unsigned char *ptr, int nb)
{
	int ret;

	if (nb == 1) {
		ret = i2c_smbus_read_byte_data(fd, reg);
		if (ret < 0) {
			fprintf(stderr,"error during read_word_data\n");
			return ret;
		}
		*ptr = (unsigned char) ret;
		return nb;
	} else if (nb == 2) {
		ret = i2c_smbus_read_word_data(fd, reg);
		if (ret < 0) {
			fprintf(stderr,"error during read_word_data\n");
			return ret;
		}
		*ptr = (u_int16_t) ret;
		return nb;
	} else {
		fprintf(stderr, "%u bytes not inplemented\n", nb);
		return -EINVAL;
	}
}
static int fan_write_reg(int reg, const unsigned char *ptr, int nb)
{
	int ret;

	if (nb == 1) {
		ret = i2c_smbus_write_byte_data(fd, reg, *ptr);
		if (ret < 0) {
			fprintf(stderr, "error during write_byte_data\n");
			return ret;
		}
		return nb;
	} else if (nb == 2) {
		ret = i2c_smbus_write_word_data(fd, reg, *ptr);
		if (ret < 0) {
			fprintf(stderr, "error during write_word_data\n");
			return ret;
		}
		return nb;
	} else {
		fprintf(stderr, "%u bytes not implemented\n", nb);
		return -EINVAL;
	}
}
#endif

static int set_rpm_fan(int fan, int rpm)
{
	unsigned char buf[2];
	int rc;

	if (rpm < 300)
		rpm = 300;
	else if (rpm > 8191)
		rpm = 8191;
	buf[0] = rpm >> 5;
	buf[1] = rpm << 3;
	rc = fan_write_reg(0x10 + (fan *2), buf, 2);
	if (rc < 0)
		return -EIO;
	return 0;
}

static int get_rpm_fan(int fan, int programmed)
{
	unsigned char failure;
	unsigned char active;
	unsigned char buf[2];
	int rc, reg_base;

	rc = fan_read_reg(0xb, &failure, 1);
	if (rc != 1) {
		fprintf(stderr, "unable to reada 0xb register\n");
		return -EIO;
	}
	if ((failure & (1 << fan)) != 0)
		return -EFAULT;
	rc = fan_read_reg(0xd, &active, 1);
	if (rc != 1) {
		fprintf(stderr, "unable to read 0xd register\n");
		return -EIO;
	}
	if ((active & (1 << fan)) == 0)
		return -ENXIO;

	reg_base = programmed ? 0x10 : 0x11;
	rc = fan_read_reg(reg_base + (fan * 2), buf, 2);
	if (rc != 2) {
		fprintf(stderr, "unable to read fan register 0x%x\n",=20
			reg_base+(fan*2));
		return -EIO;
	}

	return (buf[0] << 5 | buf[1] >> 3);
}

static int set_pwm_fan(int fan, int pwm)
{
	unsigned char buf[2];
	int rc;

	if (pwm < 10)
		pwm = 10;
	else if (pwm > 100)
		pwm = 100;
	pwm = (pwm * 2559) / 1000;
	buf[0] = pwm;
	rc = fan_write_reg(0x30 + (fan*2), buf, 1);
	if (rc < 0)
		return rc;
	return 0;
}

static int get_pwm_fan(int fan)
{
	unsigned char failure;
	unsigned char active;
	unsigned char buf[2];
	int rc;

	rc = fan_read_reg(0x2b, &failure, 1);
	if (rc != 1)
		return -EIO;
	if ((failure & (1 << fan)) != 0)
		return -EFAULT;
	rc = fan_read_reg(0x2d, &active, 1);
	if (rc != 1)
		return -EIO;
	if ((active & (1 << fan)) == 0)
		return -ENXIO;
=09
	rc = fan_read_reg(0x30 + (fan *2), buf, 1);
	if (rc != 1)
		return -EIO;

	return (buf[0] * 1000) / 2559;
}


int main(int argc, char **argv)
{
	int ret;
	int fan_num;

	fd = open("/dev/i2c-2", O_RDWR);
	if (fd < 0)
		exit(1);

	ret = ioctl(fd, I2C_SLAVE_FORCE, 0x2f);
	if (ret < 0) {
		fprintf(stderr, "Unable to access device 0x2f\n");
		exit(1);
	}

	for (fan_num = 1; fan_num <= 6; fan_num++) {
		int rpm;

		set_rpm_fan(fan_num, 3000);

		rpm = get_rpm_fan(fan_num, 0);
		if (rpm < 0)
			printf("Fan %d: %s\n", fan_num, strerror(-rpm));
		else
			printf("Fan %d: %d rpm\n", fan_num, rpm);
	}
=09
	for (fan_num = 1; fan_num <= 2; fan_num++) {
		int pwm;

		set_pwm_fan(fan_num, 30);
		pwm = get_pwm_fan(fan_num);
		if (pwm < 0)
			printf("PWM-Fan %d: %s\n", fan_num, strerror(-pwm));
		else
			printf("PWM-Fan %d: %d\n", fan_num, pwm);
	}
}

  reply	other threads:[~2004-08-06  8:04 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-08-05 11:43 [PATCH] ugly hack to make therm_pm72 work on XServe G5 Harald Welte
2004-08-06  8:04 ` Harald Welte [this message]
2004-08-06  8:09   ` Benjamin Herrenschmidt

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=20040806080406.GB11638@sunbeam2 \
    --to=laforge@gnumonks.org \
    --cc=benh@kernel.crashing.org \
    --cc=linuxppc-dev@lists.linuxppc.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).