Add hinted attachment for non-FDT systems. Also, print a message if

setting up the timer fails, because on some types of chips that's the
first attempt to access the device.  If the chip is missing/non-responsive
then you'd get a driver that attached and didn't register the rtc, with
no clue about why.  On other chip types there are inits that come before
timer setup, and they already print messages about errors.
This commit is contained in:
Ian Lepore 2017-08-14 02:23:10 +00:00
parent 1dc8df138d
commit a6e709f29c

View File

@ -191,15 +191,26 @@ struct nxprtc_softc {
u_int chiptype; /* Type of PCF85xx chip */
uint8_t secaddr; /* Address of seconds register */
uint8_t tmcaddr; /* Address of timer count register */
uint8_t slave_addr; /* PCF85xx slave address */
bool use_timer; /* Use timer for fractional sec */
};
#define SC_F_CPOL (1 << 0) /* Century bit means 19xx */
#define SC_F_AMPM (1 << 1) /* Use PM flag in hours reg */
/*
* We use the compat_data table to look up hint strings in the non-FDT case, so
* define the struct locally when we don't get it from ofw_bus_subr.h.
*/
#ifdef FDT
static struct ofw_compat_data compat_data[] = {
typedef struct ofw_compat_data nxprtc_compat_data;
#else
typedef struct {
const char *ocd_str;
uintptr_t ocd_data;
} nxprtc_compat_data;
#endif
static nxprtc_compat_data compat_data[] = {
{"nxp,pca2129", TYPE_PCA2129},
{"nxp,pca8565", TYPE_PCA8565},
{"nxp,pcf2127", TYPE_PCF2127},
@ -214,7 +225,6 @@ static struct ofw_compat_data compat_data[] = {
{NULL, TYPE_NONE},
};
#endif
static int
read_reg(struct nxprtc_softc *sc, uint8_t reg, uint8_t *val)
@ -476,19 +486,25 @@ nxprtc_start(void *dev)
case TYPE_PCF2127:
if (pcf8523_start(sc) != 0)
return;
if (pcf2127_start_timer(sc) != 0)
if (pcf2127_start_timer(sc) != 0) {
device_printf(sc->dev, "cannot set up timer\n");
return;
}
break;
case TYPE_PCF8523:
if (pcf8523_start(sc) != 0)
return;
if (pcf8523_start_timer(sc) != 0)
if (pcf8523_start_timer(sc) != 0) {
device_printf(sc->dev, "cannot set up timer\n");
return;
}
break;
case TYPE_PCA8565:
case TYPE_PCF8563:
if (pcf8563_start_timer(sc) != 0)
if (pcf8563_start_timer(sc) != 0) {
device_printf(sc->dev, "cannot set up timer\n");
return;
}
break;
default:
device_printf(sc->dev, "missing init code for this chiptype\n");
@ -684,25 +700,60 @@ nxprtc_settime(device_t dev, struct timespec *ts)
return (err);
}
static int
nxprtc_get_chiptype(device_t dev)
{
#ifdef FDT
return (ofw_bus_search_compatible(dev, compat_data)->ocd_data);
#else
nxprtc_compat_data *cdata;
const char *htype;
int chiptype;
/*
* If given a chiptype hint string, loop through the ofw compat data
* comparing the hinted chip type to the compat strings. The table end
* marker ocd_data is TYPE_NONE.
*/
if (resource_string_value(device_get_name(dev),
device_get_unit(dev), "compatible", &htype) == 0) {
for (cdata = compat_data; cdata->ocd_str != NULL; ++cdata) {
if (strcmp(htype, cdata->ocd_str) == 0)
break;
}
chiptype = cdata->ocd_data;
} else
chiptype = TYPE_NONE;
/*
* On non-FDT systems the historical behavior of this driver was to
* assume a PCF8563; keep doing that for compatibility.
*/
if (chiptype == TYPE_NONE)
return (TYPE_PCF8563);
else
return (chiptype);
#endif
}
static int
nxprtc_probe(device_t dev)
{
int chiptype;
int chiptype, rv;
#ifdef FDT
if (!ofw_bus_status_okay(dev))
return (ENXIO);
chiptype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
if (chiptype == TYPE_NONE)
return (ENXIO);
rv = BUS_PROBE_GENERIC;
#else
/* Historically the non-FDT driver supports only PCF8563. */
chiptype = TYPE_PCF8563;
rv = BUS_PROBE_NOWILDCARD;
#endif
device_set_desc(dev, desc_strings[chiptype]);
if ((chiptype = nxprtc_get_chiptype(dev)) == TYPE_NONE)
return (ENXIO);
return (BUS_PROBE_GENERIC);
device_set_desc(dev, desc_strings[chiptype]);
return (rv);
}
static int
@ -713,21 +764,9 @@ nxprtc_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
sc->busdev = device_get_parent(dev);
sc->slave_addr = iicbus_get_addr(dev);
/*
* We need to know what kind of chip we're driving. Historically the
* non-FDT driver supported only PCF8563. There is no machine-readable
* identifier in the chip so we would need a set of hints defined to use
* the other chips on non-FDT systems.
*/
#ifdef FDT
sc->chiptype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
#else
sc->chiptype = TYPE_PCF8563;
if (sc->slave_addr == 0)
sc->slave_addr = PCF8563_ADDR;
#endif
/* We need to know what kind of chip we're driving. */
sc->chiptype = nxprtc_get_chiptype(dev);
/* The features and some register addresses vary by chip type. */
switch (sc->chiptype) {