diff options
author | osaeed <none@none> | 2005-08-17 17:32:32 -0700 |
---|---|---|
committer | osaeed <none@none> | 2005-08-17 17:32:32 -0700 |
commit | afd7fd7b2e19d8a40c0b602c50de34faa641f387 (patch) | |
tree | 7a1b5247875d82170bccd052b95d170b1816cd21 | |
parent | d619c1b841dc484317f6c06b2392a6b2ae991810 (diff) | |
download | illumos-gate-afd7fd7b2e19d8a40c0b602c50de34faa641f387.tar.gz |
6273261 cpr hangs on resuming gpio@0,30
6311048 pic16f747 implementation of pcf8584 in Chicago has time delay restriction
-rw-r--r-- | usr/src/uts/sun4u/io/i2c/clients/pca9556.c | 27 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/i2c/nexus/pcf8584.c | 79 | ||||
-rw-r--r-- | usr/src/uts/sun4u/sys/i2c/nexus/pcf8584.h | 17 |
3 files changed, 104 insertions, 19 deletions
diff --git a/usr/src/uts/sun4u/io/i2c/clients/pca9556.c b/usr/src/uts/sun4u/io/i2c/clients/pca9556.c index 13cf122873..c8c4633ab2 100644 --- a/usr/src/uts/sun4u/io/i2c/clients/pca9556.c +++ b/usr/src/uts/sun4u/io/i2c/clients/pca9556.c @@ -183,6 +183,8 @@ pca9556_resume(dev_info_t *dip) int reg_offset, num_of_ports; int i, j; uint8_t reg, reg_num = 0; + extern int do_polled_io; + int saved_pio; pcap = (pca9556_unit_t *) ddi_get_soft_state(pca9556_soft_statep, instance); @@ -205,6 +207,13 @@ pca9556_resume(dev_info_t *dip) num_of_ports = PCA9556_NUM_PORTS; } + /* + * Since the parent node that handles interrupts may have already + * been suspended, perform the following i2c transfers in poll-mode. + */ + saved_pio = do_polled_io; + do_polled_io = 1; + for (i = 0; i < num_of_ports; i++) { if (pcap->pca9555_device) reg = PCA9555_OUTPUT_REG; @@ -227,14 +236,16 @@ pca9556_resume(dev_info_t *dip) } } - /* - * Clear busy flag so that transactions may continue - */ done: + do_polled_io = saved_pio; if (err != DDI_SUCCESS) { cmn_err(CE_WARN, "%s Unable to restore registers", pcap->pca9556_name); } + + /* + * Clear busy flag so that transactions may continue + */ mutex_enter(&pcap->pca9556_mutex); pcap->pca9556_flags = pcap->pca9556_flags & ~PCA9556_BUSYFLAG; cv_broadcast(&pcap->pca9556_cv); @@ -409,6 +420,8 @@ pca9556_suspend(dev_info_t *dip) int reg_offset, num_of_ports; int i, j; uint8_t reg, reg_num = 0; + extern int do_polled_io; + int saved_pio; pcap = ddi_get_soft_state(pca9556_soft_statep, instance); @@ -443,6 +456,13 @@ pca9556_suspend(dev_info_t *dip) pcap->pca9556_transfer->i2c_rlen = 1; /* + * Since the parent node that handles interrupts may have not been + * resumed yet, perform the following i2c transfers in poll-mode. + */ + saved_pio = do_polled_io; + do_polled_io = 1; + + /* * The following for loop will run through once for a pca9556 device * and twice for a pca9555 device. i will represent the port number * for the pca9555. @@ -482,6 +502,7 @@ pca9556_suspend(dev_info_t *dip) } done: + do_polled_io = saved_pio; if (err != DDI_SUCCESS) { mutex_enter(&pcap->pca9556_mutex); pcap->pca9556_flags = pcap->pca9556_flags & ~PCA9556_BUSYFLAG; diff --git a/usr/src/uts/sun4u/io/i2c/nexus/pcf8584.c b/usr/src/uts/sun4u/io/i2c/nexus/pcf8584.c index 0840d82741..56f07636a9 100644 --- a/usr/src/uts/sun4u/io/i2c/nexus/pcf8584.c +++ b/usr/src/uts/sun4u/io/i2c/nexus/pcf8584.c @@ -228,6 +228,11 @@ pcf8584_print(int flags, const char *fmt, ...) } while (0) #endif +#define PCF8584_IMPL_DELAY(type, delay) \ + if (type == PIC16F747) { \ + drv_usecwait(delay); \ + } + int _init(void) { @@ -324,6 +329,21 @@ pcf8584_doattach(dev_info_t *dip) (void) snprintf(i2c->pcf8584_name, sizeof (i2c->pcf8584_name), "%s_%d", ddi_node_name(dip), instance); + /* + * Identify which pcf8584 implementation is being attached to. + */ + if (strcmp(ddi_binding_name(i2c->pcf8584_dip), "SUNW,bbc-i2c") == 0) { + i2c->pcf8584_impl_type = BBC; + i2c->pcf8584_impl_delay = PCF8584_GENERIC_DELAY; + } else if (strcmp(ddi_binding_name(i2c->pcf8584_dip), + "SUNW,i2c-pic16f747") == 0) { + i2c->pcf8584_impl_type = PIC16F747; + i2c->pcf8584_impl_delay = PCF8584_PIC16F747_DELAY; + } else { + i2c->pcf8584_impl_type = GENERIC; + i2c->pcf8584_impl_delay = PCF8584_GENERIC_DELAY; + } + if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "interrupt-priorities") != 1) { @@ -741,10 +761,14 @@ pcf8584_put_s1(pcf8584_t *i2c, char cmd) pcf8584_regs_t *rp = &i2c->pcf8584_regs; ddi_put8(hp, rp->pcf8584_regs_s1, cmd); + PCF8584_IMPL_DELAY(i2c->pcf8584_impl_type, + i2c->pcf8584_impl_delay); /* * read status to make sure write is flushed */ (void) ddi_get8(hp, rp->pcf8584_regs_s1); + PCF8584_IMPL_DELAY(i2c->pcf8584_impl_type, + i2c->pcf8584_impl_delay); } /* @@ -757,10 +781,14 @@ pcf8584_put_s0(pcf8584_t *i2c, char data) pcf8584_regs_t *rp = &i2c->pcf8584_regs; ddi_put8(hp, rp->pcf8584_regs_s0, data); + PCF8584_IMPL_DELAY(i2c->pcf8584_impl_type, + i2c->pcf8584_impl_delay); /* * read status to make sure write is flushed */ (void) ddi_get8(hp, rp->pcf8584_regs_s1); + PCF8584_IMPL_DELAY(i2c->pcf8584_impl_type, + i2c->pcf8584_impl_delay); } /* @@ -771,8 +799,13 @@ pcf8584_get_s0(pcf8584_t *i2c) { ddi_acc_handle_t hp = i2c->pcf8584_rhandle; pcf8584_regs_t *rp = &i2c->pcf8584_regs; + uint8_t s0; - return (ddi_get8(hp, rp->pcf8584_regs_s0)); + s0 = ddi_get8(hp, rp->pcf8584_regs_s0); + PCF8584_IMPL_DELAY(i2c->pcf8584_impl_type, + i2c->pcf8584_impl_delay); + + return (s0); } /* @@ -783,8 +816,13 @@ pcf8584_get_s1(pcf8584_t *i2c) { ddi_acc_handle_t hp = i2c->pcf8584_rhandle; pcf8584_regs_t *rp = &i2c->pcf8584_regs; + uint8_t s1; - return (ddi_get8(hp, rp->pcf8584_regs_s1)); + s1 = ddi_get8(hp, rp->pcf8584_regs_s1); + PCF8584_IMPL_DELAY(i2c->pcf8584_impl_type, + i2c->pcf8584_impl_delay); + + return (s1); } /* @@ -965,7 +1003,7 @@ pcf8584_init(pcf8584_t *i2c) * BBC based systems are using the Safari clock as input, so select * the clk divisor based on it. */ - if (strcmp(ddi_binding_name(i2c->pcf8584_dip), "SUNW,bbc-i2c") == 0) { + if (i2c->pcf8584_impl_type == BBC) { dev_info_t *root_node; int clock_freq; root_node = ddi_root_node(); @@ -1029,7 +1067,7 @@ pcf8584_setup_regs(dev_info_t *dip, pcf8584_t *i2c) /* * If i2c controller is on BBC, then s1 comes before s0. */ - if (strcmp(ddi_binding_name(dip), "SUNW,bbc-i2c") == 0) { + if (i2c->pcf8584_impl_type == BBC) { i2c->pcf8584_regs.pcf8584_regs_s0 = (uint8_t *)®_base[1]; i2c->pcf8584_regs.pcf8584_regs_s1 = @@ -1107,6 +1145,7 @@ pcf8584_intr(caddr_t arg) pcf8584_t *i2c = (pcf8584_t *)arg; uint8_t s1; + ASSERT(i2c->pcf8584_mode != PCF8584_POLL_MODE); PCF8584_DDB(pcf8584_print(PRT_INTR, "pcf8584_intr: enter\n")); mutex_enter(&i2c->pcf8584_imutex); @@ -1186,7 +1225,10 @@ pcf8584_process(pcf8584_t *i2c, uint8_t s1) if (tp->i2c_flags == I2C_RD) { addr |= I2C_READ; } - pcf8584_put_s1(i2c, S1_START2 | S1_ENI); + if (i2c->pcf8584_mode == PCF8584_POLL_MODE) + pcf8584_put_s1(i2c, S1_START2); + else + pcf8584_put_s1(i2c, S1_START2 | S1_ENI); pcf8584_put_s0(i2c, addr); PCF8584_DDB(pcf8584_print(PRT_TRAN, "TRAN_STATE_START: write addr: %x\n", addr)); @@ -1235,7 +1277,10 @@ pcf8584_process(pcf8584_t *i2c, uint8_t s1) * to be sent on the I2C bus. */ if (tp->i2c_r_resid == 1) { - pcf8584_put_s1(i2c, S1_ESO | S1_ENI); + if (i2c->pcf8584_mode == PCF8584_POLL_MODE) + pcf8584_put_s1(i2c, S1_ESO); + else + pcf8584_put_s1(i2c, S1_ESO | S1_ENI); } /* @@ -1272,7 +1317,10 @@ pcf8584_process(pcf8584_t *i2c, uint8_t s1) * don't want to be ACK'd, so clear the ACK bit. */ if (tp->i2c_r_resid == 2) { - pcf8584_put_s1(i2c, S1_ESO | S1_ENI); + if (i2c->pcf8584_mode == PCF8584_POLL_MODE) + pcf8584_put_s1(i2c, S1_ESO); + else + pcf8584_put_s1(i2c, S1_ESO | S1_ENI); } tp->i2c_rbuf[tp->i2c_rlen - tp->i2c_r_resid] = @@ -1312,7 +1360,10 @@ pcf8584_process(pcf8584_t *i2c, uint8_t s1) tp->i2c_wbuf[tp->i2c_wlen - (tp->i2c_w_resid + 1)])); } else { - pcf8584_put_s1(i2c, S1_START2 | S1_ENI); + if (i2c->pcf8584_mode == PCF8584_POLL_MODE) + pcf8584_put_s1(i2c, S1_START2); + else + pcf8584_put_s1(i2c, S1_START2 | S1_ENI); pcf8584_put_s0(i2c, addr | I2C_READ); i2c->pcf8584_tran_state = TRAN_STATE_DUMMY_RD; @@ -1357,7 +1408,7 @@ begin: * we need to usurp ownership of the I2C bus, bypassing any other * waiters. */ - if ((do_polled_io || ddi_in_panic()) && (getpil() >= pcf8584_pil)) { + if (do_polled_io || ddi_in_panic()) { pcf8584_take_over(i2c, dip, tp, &waiter, &saved_mode); took_over = 1; } else { @@ -1400,7 +1451,10 @@ begin: pcf8584_put_s0(i2c, DUMMY_ADDR); PCF8584_DDB(pcf8584_print(PRT_TRAN, "FIRST WRITE DUMMY ADDR: write %x\n", DUMMY_ADDR)); - pcf8584_put_s1(i2c, S1_START | S1_ENI); + if (i2c->pcf8584_mode == PCF8584_POLL_MODE) + pcf8584_put_s1(i2c, S1_START); + else + pcf8584_put_s1(i2c, S1_START | S1_ENI); /* * Update transfer status so any polled i/o request coming in @@ -1463,6 +1517,8 @@ pcf8584_take_over(pcf8584_t *i2c, dev_info_t *dip, i2c_transfer_t *tp, kcondvar_t **waiter, int *saved_mode) { mutex_enter(&i2c->pcf8584_imutex); + *saved_mode = i2c->pcf8584_mode; + i2c->pcf8584_mode = PCF8584_POLL_MODE; /* * We need to flush out any currently pending transaction before @@ -1482,9 +1538,6 @@ pcf8584_take_over(pcf8584_t *i2c, dev_info_t *dip, i2c_transfer_t *tp, * the 'force' flag on. */ pcf8584_acquire(i2c, dip, tp, B_TRUE); - - *saved_mode = i2c->pcf8584_mode; - i2c->pcf8584_mode = PCF8584_POLL_MODE; } /* diff --git a/usr/src/uts/sun4u/sys/i2c/nexus/pcf8584.h b/usr/src/uts/sun4u/sys/i2c/nexus/pcf8584.h index e65d741ce8..491124ee77 100644 --- a/usr/src/uts/sun4u/sys/i2c/nexus/pcf8584.h +++ b/usr/src/uts/sun4u/sys/i2c/nexus/pcf8584.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -110,6 +110,15 @@ enum tran_state { TRAN_STATE_DUMMY_RD }; +/* + * different implementations of pcf8584 + */ +enum impl_type { + GENERIC, + BBC, + PIC16F747 +}; + typedef struct pcf8584_regs { uint8_t *pcf8584_regs_s0; uint8_t *pcf8584_regs_s1; @@ -136,6 +145,8 @@ typedef struct pcf8584 { ddi_acc_handle_t pcf8584_b_rhandle; enum tran_state pcf8584_tran_state; char pcf8584_name[12]; + enum impl_type pcf8584_impl_type; + uint32_t pcf8584_impl_delay; } pcf8584_t; /* @@ -151,11 +162,11 @@ typedef struct pcf8584_ppvt { } pcf8584_ppvt_t; #define PCF8584_PIL 4 -#define PCF8584_XFER_TIME 1000 -#define PCF8584_INTR_OVERHEAD 2000000 #define PCF8584_POLL_MODE 1 #define PCF8584_INTR_MODE 2 #define PCF8584_INITIAL_SOFT_SPACE 4 +#define PCF8584_GENERIC_DELAY 0 +#define PCF8584_PIC16F747_DELAY 10 /* * generic interrupt return values |