LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Embedded & Single-board computer (https://www.linuxquestions.org/questions/linux-embedded-and-single-board-computer-78/)
-   -   How to reverse sda/scl pins in s3c2410 i2c drivers? (https://www.linuxquestions.org/questions/linux-embedded-and-single-board-computer-78/how-to-reverse-sda-scl-pins-in-s3c2410-i2c-drivers-844448/)

mj1856 11-15-2010 05:02 PM

How to reverse sda/scl pins in s3c2410 i2c drivers?
 
Hi. I'm working with a custom s3c2410 board, and I have an interesting delima. The company I work for had this board made a long time ago, and they based everything on the 2.4.18 kernel from the old Mizi Linux. I've been working with getting everything working on a standard 2.6 kernel. So far so good - I've had success in many areas, but I'm stuck on one major problem.

The original designers opted to not use the RTC internal to the s3c2410. Instead, they attached an s35390a to the i2c bus. The problem is that when they wired it up, they messed up and swapped the SDA and SCL lines. So when I try to load the driver, of course it can't find the device at all. I need a software solution - cutting the lines on the PCB and rewiring them is not an option, due to the vast quantity already produced.

Now the old 2.4 kernel appears to be working ok, but they did not use any standard driver. They hacked apart the rtc driver and put their own codes in. Not acceptable in my book. I should just be able to use the standard s35390a driver under 2.6. I haven't been able to follow their hacks well enough to figure out how they dealt with the swapped lines. Not sure if it would even help anyway.

So the question is, how do I tell the i2c bus that I have a device with swapped pins? It is the only device on the bus, so I'm ok swapping the i2c pins themselves.

I found in /arch/arm/plat/s3c24xx/setup-i2c.c where the default gpios are configured for the i2c bus:

void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
}

I tried changing them such as:

void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE15_IICSDA);
s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE14_IICSCL);
}

But that doesn't seem to help at all. I just get the following in my startup dmesg either way:

rtc-s35390a 0-0030: error resetting chip
rtc-s35390a: probe of 0-0030 failed with error -5
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)

I have the board config all set to go for the standard s35390a driver, I just can't figure out how to swap the lines.

Any help is greatly appreciated.

-Matt

petaflot 11-16-2010 05:57 AM

what you did makes sense.

you might want to try to swap the pins the hardware way JUST FOR ONE BOARD, to make sure your driver works ok the way it's intended to do.

if that test is successful, check the datasheet of the s3c2410. can the pins really be assigned dynamically? if not, you're screwed. if yes, you missed something in the source.

mj1856 11-16-2010 01:33 PM

Ok, based on your recomendation, I tried swapping the pins on my test board and leaving the i2c driver alone. It still doesn't work, so I think there is something else going on here with the s3c2410-i2c driver, or with my external rtc.

I've been using the i2ctools from the lmsensors project to help with testing. Specifically, i2cdetect and i2cdump.

The good news is that I get the same results from i2cdetect using either the software swap (as posted above), or the phsical hardware swap. So, I would guess that the software swap will indeed work once I figure the rest out.

The bad news is now that with the pins wrong, i2cdetect completes but shows no results. With the pins correct, i2cdetect hangs and immediately starts throwing this error repeatedly:

s3c-i2c s3c2410-i2c: cannot get bus (error -110)

Any ideas?

One other thing - the RTC chip is labeled S35390, but the only linux driver is for S35390A. I can't even find a datasheet on S35390, only the "A" model. I assume that the difference isn't important for my purposes, but who knows. At any rate, the driver doesn't even load because of the i2c problems, so I don't think it's important.

The only thing I could find on google about the error -100 is an old patch to openmoko - which basically implemented suspend/resume functions. I found that similar code is already implemented in the current 2.6.36 kernel I'm using, but it only invokes with CONFIG_PM enabled (power management). I re-build my kernel to enable CONFIG_PM and tried again, but got the same results.

Any other ideas?
Thanks,
Matt

petaflot 11-17-2010 12:40 PM

do you have the hardware to see what's on the lines? an oscilloscope or a tool like http://dangerousprototypes.com/docs/Bus_Pirate would be needed, as well as good knowledge of what's supposed to happen.

if googleing the error code doesn't work, read the source (luke).

maybe your test board is broken. now you know the soft swapping works, try another board? maybe it helps.

mj1856 11-17-2010 06:22 PM

No scope or bus pirate, but I do have a simple logic probe. Maybe I can figure out what's going on physically.

From the source, looks like that error is from my i2c bus driver and the error is a simple timeout trying to set the i2c bus to master mode.

Source: http://bit.ly/b7JlFt

I'm starting to wonder if the device is wired backwards because the cpu is hooked up backwards too, so really it's wired correctly. (two wrongs make a right in some countries...) So maybe it's not backwards at all and I'm just having driver issues.

Anyone know if the s35390 is a different animal than the s35390a? The only drivers I see anywhere are for the "a" model, so that's what I'm trying to use.

Either way, wouldn't i2cdetect find something out there even if I had the wrong driver?

I've been researching all I can about i2c and so far it looks like I'm doing it right, so I'm not sure what to try next.

Regards,
Matt

mj1856 11-17-2010 06:31 PM

I suppose it would help if I posted the related sections of my machine config (from /arch/arm/mach-s3c2410/mach-myboard.c)

static struct i2c_board_info myboard_i2c_devs[] __initdata = {
{
I2C_BOARD_INFO("s35390a", 0x30),
},
};

static void __init myboard_machine_init(void)
{
...
i2c_register_board_info(0, myboard_i2c_devs, ARRAY_SIZE(myboard_i2c_devs));
...
}

-Matt

mj1856 11-18-2010 02:44 PM

Solved
 
I did some testing and got it to work.

Basically, I disabled the i2c bus drivers and then used the /sys/class/gpio interface to toggle the pins while testing the output with a logic probe on the lines to my rtc. Using this method, I was able to confirm the pins were indeed swaped (SDA on GPE14 and SCL on GPE15). While this wasn't the key to the solution, I thought I would post this simple techinique in case others may find it useful.

What actually solved my problem was switching from the s3c-i2c driver to the generic i2c-gpio driver. I tried this on a whim without thinking much would come of it, but it worked! Maybe someone can shed light on why. I tried the same pin and delay settings in the s3c-i2c driver without success. No changes were necessary to the rtc configuration. Here is my device setup for the i2c-gpio driver:

static struct i2c_gpio_platform_data myboard_i2c_gpio_data = {
.sda_pin = S3C2410_GPE(14),
.scl_pin = S3C2410_GPE(15),
.udelay = 50, /* 10 kHz */
};

static struct platform_device myboard_i2c_gpio = {
.name = "i2c-gpio",
.id = 0,
.dev = {
.platform_data = &myboard_i2c_gpio_data,
},
};

Then it's just a matter of adding &myboard_i2c_gpio to the device list.

Any idea why the gpio-i2c driver worked but the s3c-i2c driver didn't?

Anyway, thanks for the help.
-Matt

petaflot 11-19-2010 05:17 AM

thanks for the update. for your question, you might get an answer on the i2c kernel mailing list...

linux-i2c at vger.kernel.org

l2y3n2 11-23-2010 12:15 AM

Quote:

Originally Posted by mj1856 (Post 4159957)
void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
}

I tried changing them such as:

void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE15_IICSDA);
s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE14_IICSCL);
}
-Matt

What you do here is simply configure the input/output status for GPIO GPE14 and GPE15 (Defined in arch/arm/mach-s3c2410/include/mach/regs-gpio.h), but the actual i2c output is controller by I2C Controller and would not invert SCL/SDA signals at all.

In fact you can't invert the two pins if you are using the hardware controller (it doesn't support it).

The only solution is to use gpio-base emulation as you did(it use the same pins but your data is sent/recv through i2c-bus by kernel, pulling up/down the two pins to emulate i2c output).

That way needs more cpu instructions but since your i2c is a rtc device, that's ok (it only reads once at boot-up and writes to at shut-down).


All times are GMT -5. The time now is 01:51 AM.