/* * Perform some start-of-day setup, including reading the asa calibration * values and caching them. */ static int ak8975_setup(struct i2c_client *client) { struct ak8975_data *data = i2c_get_clientdata(client); u8 device_id; int ret; /* Confirm that the device we're talking to is really an AK8975. */ ret = ak8975_read_data(client, AK8975_REG_WIA, 1, &device_id); if (ret < 0) { dev_err(&client->dev, "Error reading WIA\n"); return ret; } if (device_id != AK8975_DEVICE_ID) { dev_err(&client->dev, "Device ak8975 not found\n"); return -ENODEV; } /* Write the fused rom access mode. */ ret = ak8975_write_data(client, AK8975_REG_CNTL, AK8975_REG_CNTL_MODE_FUSE_ROM, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); if (ret < 0) { dev_err(&client->dev, "Error in setting fuse access mode\n"); return ret; } /* Get asa data and store in the device data. */ ret = ak8975_read_data(client, AK8975_REG_ASAX, 3, data->asa); if (ret < 0) { dev_err(&client->dev, "Not able to read asa data\n"); return ret; } /* Precalculate scale factor for each axis and store in the device data. */ data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8; data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8; data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8; return 0; }
/* * Sets the device's mode. 0 = off, 1 = on. The device's mode must be on * for the magn raw attributes to be available. */ static ssize_t store_mode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ak8975_data *data = indio_dev->dev_data; struct i2c_client *client = data->client; unsigned long oval; int ret; /* Convert mode string and do some basic sanity checking on it. only 0 or 1 are valid. */ if (strict_strtoul(buf, 10, &oval)) return -EINVAL; if (oval > 1) { dev_err(dev, "mode value is not supported\n"); return -EINVAL; } mutex_lock(&data->lock); /* Write the mode to the device. */ if (data->mode != oval) { ret = ak8975_write_data(client, AK8975_REG_CNTL, (u8)oval, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); if (ret < 0) { dev_err(&client->dev, "Error in setting mode\n"); mutex_unlock(&data->lock); return ret; } data->mode = oval; } mutex_unlock(&data->lock); return count; }
/* * Emits the raw flux value for the x, y, or z axis. */ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) { struct ak8975_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; u16 meas_reg; s16 raw; int ret; mutex_lock(&data->lock); /* Set up the device for taking a sample. */ ret = ak8975_write_data(client, AK8975_REG_CNTL, AK8975_REG_CNTL_MODE_ONCE, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); if (ret < 0) { dev_err(&client->dev, "Error in setting operating mode\n"); goto exit; } /* Wait for the conversion to complete. */ if (gpio_is_valid(data->eoc_gpio)) ret = wait_conversion_complete_gpio(data); else ret = wait_conversion_complete_polled(data); if (ret < 0) goto exit; if (ret & AK8975_REG_ST1_DRDY_MASK) { ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2); if (ret < 0) { dev_err(&client->dev, "Error in reading ST2\n"); goto exit; } if (ret & (AK8975_REG_ST2_DERR_MASK | AK8975_REG_ST2_HOFL_MASK)) { dev_err(&client->dev, "ST2 status error 0x%x\n", ret); ret = -EINVAL; goto exit; } } /* Read the flux value from the appropriate register (the register is specified in the iio device attributes). */ ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]); if (ret < 0) { dev_err(&client->dev, "Read axis data fails\n"); goto exit; } meas_reg = ret; mutex_unlock(&data->lock); /* Endian conversion of the measured values. */ raw = (s16) (le16_to_cpu(meas_reg)); /* Clamp to valid range. */ raw = clamp_t(s16, raw, -4096, 4095); *val = raw; return IIO_VAL_INT; exit: mutex_unlock(&data->lock); return ret; }
/* * Perform some start-of-day setup, including reading the asa calibration * values and caching them. */ static int ak8975_setup(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct ak8975_data *data = iio_priv(indio_dev); u8 device_id; int ret; /* Confirm that the device we're talking to is really an AK8975. */ ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA); if (ret < 0) { dev_err(&client->dev, "Error reading WIA\n"); return ret; } device_id = ret; if (device_id != AK8975_DEVICE_ID) { dev_err(&client->dev, "Device ak8975 not found\n"); return -ENODEV; } /* Write the fused rom access mode. */ ret = ak8975_write_data(client, AK8975_REG_CNTL, AK8975_REG_CNTL_MODE_FUSE_ROM, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); if (ret < 0) { dev_err(&client->dev, "Error in setting fuse access mode\n"); return ret; } /* Get asa data and store in the device data. */ ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX, 3, data->asa); if (ret < 0) { dev_err(&client->dev, "Not able to read asa data\n"); return ret; } /* After reading fuse ROM data set power-down mode */ ret = ak8975_write_data(client, AK8975_REG_CNTL, AK8975_REG_CNTL_MODE_POWER_DOWN, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); if (ret < 0) { dev_err(&client->dev, "Error in setting power-down mode\n"); return ret; } /* * Precalculate scale factor (in Gauss units) for each axis and * store in the device data. * * This scale factor is axis-dependent, and is derived from 3 calibration * factors ASA(x), ASA(y), and ASA(z). * * These ASA values are read from the sensor device at start of day, and * cached in the device context struct. * * Adjusting the flux value with the sensitivity adjustment value should be * done via the following formula: * * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 ) * * where H is the raw value, ASA is the sensitivity adjustment, and Hadj * is the resultant adjusted value. * * We reduce the formula to: * * Hadj = H * (ASA + 128) / 256 * * H is in the range of -4096 to 4095. The magnetometer has a range of * +-1229uT. To go from the raw value to uT is: * * HuT = H * 1229/4096, or roughly, 3/10. * * Since 1uT = 100 gauss, our final scale factor becomes: * * Hadj = H * ((ASA + 128) / 256) * 3/10 * 100 * Hadj = H * ((ASA + 128) * 30 / 256 * * Since ASA doesn't change, we cache the resultant scale factor into the * device context in ak8975_setup(). */ data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8; data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8; data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8; return 0; }
/* * Emits the raw flux value for the x, y, or z axis. */ static ssize_t show_raw(struct device *dev, struct device_attribute *devattr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ak8975_data *data = indio_dev->dev_data; struct i2c_client *client = data->client; struct iio_dev_attr *this_attr = to_iio_dev_attr(devattr); u16 meas_reg; s16 raw; u8 read_status; int ret; mutex_lock(&data->lock); if (data->mode == 0) { dev_err(&client->dev, "Operating mode is in power down mode\n"); ret = -EBUSY; goto exit; } /* Set up the device for taking a sample. */ ret = ak8975_write_data(client, AK8975_REG_CNTL, AK8975_REG_CNTL_MODE_ONCE, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); if (ret < 0) { dev_err(&client->dev, "Error in setting operating mode\n"); goto exit; } /* Wait for the conversion to complete. */ if (data->eoc_gpio) ret = wait_conversion_complete_gpio(data); else ret = wait_conversion_complete_polled(data); if (ret < 0) goto exit; read_status = ret; if (read_status & AK8975_REG_ST1_DRDY_MASK) { ret = ak8975_read_data(client, AK8975_REG_ST2, 1, &read_status); if (ret < 0) { dev_err(&client->dev, "Error in reading ST2\n"); goto exit; } if (read_status & (AK8975_REG_ST2_DERR_MASK | AK8975_REG_ST2_HOFL_MASK)) { dev_err(&client->dev, "ST2 status error 0x%x\n", read_status); ret = -EINVAL; goto exit; } } /* Read the flux value from the appropriate register (the register is specified in the iio device attributes). */ ret = ak8975_read_data(client, this_attr->address, 2, (u8 *)&meas_reg); if (ret < 0) { dev_err(&client->dev, "Read axis data fails\n"); goto exit; } mutex_unlock(&data->lock); /* Endian conversion of the measured values. */ raw = (s16) (le16_to_cpu(meas_reg)); /* Clamp to valid range. */ raw = clamp_t(s16, raw, -4096, 4095); return sprintf(buf, "%d\n", raw); exit: mutex_unlock(&data->lock); return ret; }