From patchwork Tue Jan 27 07:15:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 5715121 X-Patchwork-Delegate: eduardo.valentin@ti.com Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 6A257C058D for ; Tue, 27 Jan 2015 07:15:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6DC85201F2 for ; Tue, 27 Jan 2015 07:15:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 444E8201FE for ; Tue, 27 Jan 2015 07:15:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754023AbbA0HP3 (ORCPT ); Tue, 27 Jan 2015 02:15:29 -0500 Received: from mail-we0-f176.google.com ([74.125.82.176]:33010 "EHLO mail-we0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752270AbbA0HP2 (ORCPT ); Tue, 27 Jan 2015 02:15:28 -0500 Received: by mail-we0-f176.google.com with SMTP id w62so13159678wes.7 for ; Mon, 26 Jan 2015 23:15:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:message-id:date:from:user-agent:mime-version:to :cc:subject:references:in-reply-to:content-type :content-transfer-encoding; bh=521RsVab8mTMKM8vv4d3FIrJr9TvXW9RCGtwG3PHTcE=; b=DiFWG0mqf25D5w6IrvP8oCQbDG1tsgaxuKmJtpyqbT1q0kHpI/JEAHo7YgxErzlL8y F+BgvpUd2nrP6BlZdxC3wyA6jHrZY2JCTFLqmZEqLsF/3kjPQH4UbYPGIo046D5esZ0S gWeOmN2kcTX/FsNqsaSDkAs3TiDLZdon6b6mgF7XR9qJ3UlxgXu7ElfMh+5xcAWoTyNb vT5yhykxKoHAaDxDiRQA7KgkGEu51tOaHhl1ix0/TLOYF4HzU5Al8MB0Pb34FKfvSpPl pY7FEKBGW7L52oaYJ5997e7uXGmVvhswryRlmEBeI2J+kQ8wz4FMh2/6tzPz9apKFBQh 42eQ== X-Gm-Message-State: ALoCoQmUk7nkdv8mAQtEGpdGqhcAwInL3mnqtkmiKpHlq3HI115VCP7qJ2LefAKY77pHxyQhfqG4 X-Received: by 10.180.79.233 with SMTP id m9mr40681790wix.15.1422342926437; Mon, 26 Jan 2015 23:15:26 -0800 (PST) Received: from [192.168.1.11] (host-2-98-216-248.as13285.net. [2.98.216.248]) by mx.google.com with ESMTPSA id fp2sm16876147wib.8.2015.01.26.23.15.24 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 26 Jan 2015 23:15:25 -0800 (PST) Message-ID: <54C73B0B.609@linaro.org> Date: Tue, 27 Jan 2015 07:15:23 +0000 From: Srinivas Kandagatla User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Narendran Rajan , Zhang Rui , Eduardo Valentin CC: Linux ARM MSM , Linux PM , Siddartha Mohanadoss , Stephen Boyd Subject: Re: [PATCH] thermal: Add msm tsens thermal sensor driver References: <1422331786-19620-1-git-send-email-nrajan@codeaurora.org> In-Reply-To: <1422331786-19620-1-git-send-email-nrajan@codeaurora.org> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Thankyou for sending the patch.. here are some comments On 27/01/15 04:09, Narendran Rajan wrote: ... > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include ?? > +#include ??? > +#include > +#include > + > +/* Trips: from very hot to very cold */ > +enum tsens_trip_type { > + TSENS_TRIP_STAGE3, > + TSENS_TRIP_STAGE2, > + TSENS_TRIP_STAGE1, > + TSENS_TRIP_STAGE0, > + TSENS_TRIP_NUM, > +}; Do you need this if trips are actually coming from DT? > + > +#define TSENS_CAL_MDEGC 30000 > + > +#define TSENS_MAX_SENSORS 11 > + > +#define TSENS_8960_CONFIG_ADDR 0x3640 > +#define TSENS_8960_CONFIG 0x9b > +#define TSENS_8960_CONFIG_MASK 0xf > + > +#define TSENS_CNTL_ADDR 0x3620 > +#define TSENS_CNTL_RESUME_MASK 0xfffffff9 > +#define TSENS_EN BIT(0) > +#define TSENS_SW_RST BIT(1) > +#define SENSOR0_EN BIT(3) > +#define TSENS_MIN_STATUS_MASK BIT(0) > +#define TSENS_LOWER_STATUS_CLR BIT(1) > +#define TSENS_UPPER_STATUS_CLR BIT(2) > +#define TSENS_MAX_STATUS_MASK BIT(3) > +#define TSENS_MEASURE_PERIOD 1 > +#define TSENS_8960_SLP_CLK_ENA BIT(26) > +#define TSENS_8660_SLP_CLK_ENA BIT(24) > +#define TSENS_8064_STATUS_CNTL 0x3660 > + > +#define TSENS_THRESHOLD_ADDR 0x3624 > +#define TSENS_THRESHOLD_MAX_CODE 0xff > +#define TSENS_THRESHOLD_MIN_CODE 0 > +#define TSENS_THRESHOLD_MAX_LIMIT_SHIFT 24 > +#define TSENS_THRESHOLD_MIN_LIMIT_SHIFT 16 > +#define TSENS_THRESHOLD_UPPER_LIMIT_SHIFT 8 > +#define TSENS_THRESHOLD_LOWER_LIMIT_SHIFT 0 > + > +/* Initial temperature threshold values */ > +#define TSENS_LOWER_LIMIT_TH 0x50 > +#define TSENS_UPPER_LIMIT_TH 0xdf > +#define TSENS_MIN_LIMIT_TH 0x0 > +#define TSENS_MAX_LIMIT_TH 0xff > + > +#define TSENS_S0_STATUS_ADDR 0x3628 > + > +#define TSENS_INT_STATUS_ADDR 0x363c > +#define TSENS_LOWER_INT_MASK BIT(1) > +#define TSENS_UPPER_INT_MASK BIT(2) > +#define TSENS_MAX_INT_MASK BIT(3) > +#define TSENS_TRDY_MASK BIT(7) > + > +#define TSENS_SENSOR_SHIFT 16 > +#define TSENS_REDUND_SHIFT 24 > +#define TSENS_SENSOR0_SHIFT 3 > + > +#define TSENS_8660_QFPROM_ADDR 0x00bc ?? Why is this offset defined in the driver, Is'nt this supposed to come via dt? > +#define TSENS_8660_CONFIG 1 > +#define TSENS_8660_CONFIG_SHIFT 28 > +#define TSENS_8660_CONFIG_MASK (3 << TSENS_8660_CONFIG_SHIFT) > + > +struct tsens_device; > + > +struct tsens_sensor { > + struct thermal_zone_device *tz_dev; > + enum thermal_device_mode mode; > + unsigned int sensor_num; > + int offset; > + u32 slope; > + struct tsens_device *tmdev; > + u32 status; > +}; > + > +struct tsens_device { > + bool prev_reading_avail; > + unsigned int num_sensors; > + int pm_tsens_thr_data; > + int pm_tsens_cntl; > + unsigned int calib_offset; > + unsigned int backup_calib_offset; > + struct work_struct tsens_work; > + struct regmap *map; > + struct regmap_field *status_field; > + struct tsens_sensor sensor[0]; > +}; > + > +static struct device *tsens_dev; Hmm.. I think you should remove this global variable and find a better way to get hold of this. > + > +/* Temperature on y axis and ADC-code on x-axis */ > +static int > +tsens_tz_code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) > +{ > + return adc_code * s->slope + s->offset; > +} > + > +static int tsens_tz_get_temp(void *_sensor, > + long *temp) > +{ > + const struct tsens_sensor *tm_sensor = _sensor; > + struct tsens_device *tmdev = tm_sensor->tmdev; > + u32 code, trdy; > + > + if (tm_sensor->mode != THERMAL_DEVICE_ENABLED) > + return -EINVAL; > + > + if (!tmdev->prev_reading_avail) { > + while (!regmap_read(tmdev->map, TSENS_INT_STATUS_ADDR, &trdy) && > + !(trdy & TSENS_TRDY_MASK)) > + usleep_range(1000, 1100); > + tmdev->prev_reading_avail = true; > + } > + > + regmap_read(tmdev->map, tm_sensor->status, &code); > + *temp = tsens_tz_code_to_mdegC(code, tm_sensor); > + > + dev_dbg(tsens_dev, "Temperature for sensor %d is: %ld", > + tm_sensor->sensor_num, *temp); > + > + return 0; > +} > + > +/* > + * If the main sensor is disabled all the sensors are disable and > + * the clock is disabled. > + * If the main sensor is disabled and a sub-sensor is enabled > + * return with an error. > + */ > +static int tsens_tz_set_mode(struct tsens_sensor *tm_sensor, > + enum thermal_device_mode mode) > +{ > + struct tsens_device *tmdev = tm_sensor->tmdev; > + unsigned int i, n = tmdev->num_sensors; > + u32 reg, mask; > + > + if (mode == tm_sensor->mode) > + return 0; > + > + regmap_read(tmdev->map, TSENS_CNTL_ADDR, ®); > + > + mask = BIT(tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT); > + if (mode == THERMAL_DEVICE_ENABLED) { > + if (!(reg & SENSOR0_EN) && mask != SENSOR0_EN) { > + pr_err("Main sensor not enabled\n"); > + return -EINVAL; > + } > + > + regmap_write(tmdev->map, TSENS_CNTL_ADDR, reg | TSENS_SW_RST); > + if (tmdev->num_sensors > 1) > + reg |= mask | TSENS_8960_SLP_CLK_ENA | TSENS_EN; > + else > + reg |= mask | TSENS_8660_SLP_CLK_ENA | TSENS_EN; > + tmdev->prev_reading_avail = false; > + } else { > + reg &= ~mask; > + if (!(reg & SENSOR0_EN)) { > + dev_warn(tsens_dev, "Main sensor not enabled. Disabling subsensors\n"); > + > + reg &= ~GENMASK(n + TSENS_SENSOR0_SHIFT - 1, > + TSENS_SENSOR0_SHIFT); > + reg &= ~TSENS_EN; > + > + if (tmdev->num_sensors > 1) > + reg &= ~TSENS_8960_SLP_CLK_ENA; > + else > + reg &= ~TSENS_8660_SLP_CLK_ENA; > + > + /* Disable all sub-sensors */ > + for (i = 1; i < n; i++) > + tmdev->sensor[i].mode = mode; > + } > + } > + > + regmap_write(tmdev->map, TSENS_CNTL_ADDR, reg); > + tm_sensor->mode = mode; > + > + return 0; > +} > + > +#ifdef THERMAL_TSENS8960_HWTRIPS Should this be a kernel config? Or by default this should'nt be On? Do you need this code if the trip values are actually coming from DT? > +static int tsens_get_trip_temp(struct tsens_sensor *tm_sensor, > + int trip, int *temp) > +{ > + struct tsens_device *tmdev = tm_sensor->tmdev; > + u32 reg; > + > + regmap_read(tmdev->map, TSENS_THRESHOLD_ADDR, ®); > + switch (trip) { > + case TSENS_TRIP_STAGE3: > + reg >>= TSENS_THRESHOLD_MAX_LIMIT_SHIFT; > + break; > + case TSENS_TRIP_STAGE2: > + reg >>= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT; > + break; > + case TSENS_TRIP_STAGE1: > + reg >>= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT; > + break; > + case TSENS_TRIP_STAGE0: > + reg >>= TSENS_THRESHOLD_MIN_LIMIT_SHIFT; > + break; > + default: > + return -EINVAL; > + } > + reg &= TSENS_THRESHOLD_MAX_CODE; > + > + temp = tsens_tz_code_to_mdegC(reg, tm_sensor); > + > + dev_dbg(tsens_dev, "Sensor %d, trip %d temp is :%d", > + tm_sensor->sensor_num, trip, *temp); > + > + return 0; > +} > + > +static void tsens_print_trip_temp(struct tsens_sensor *tm_sensor) > +{ > + int temp; > + > + tsens_get_trip_temp(tm_sensor, TSENS_TRIP_STAGE0, &temp); > + tsens_get_trip_temp(tm_sensor, TSENS_TRIP_STAGE1, &temp); > + tsens_get_trip_temp(tm_sensor, TSENS_TRIP_STAGE2, &temp); > + tsens_get_trip_temp(tm_sensor, TSENS_TRIP_STAGE3, &temp); > +} > + > +static int tsens_tz_mdegC_to_code(int mdegC, const struct tsens_sensor *s) > +{ > + int code; > + > + code = DIV_ROUND_CLOSEST(mdegC - s->offset, s->slope); > + return clamp(code, TSENS_THRESHOLD_MIN_CODE, TSENS_THRESHOLD_MAX_CODE); > +} > + > +static u32 tsens_hi_code(int trip, u32 reg_cntl, u32 thresh) > +{ > + u32 hi_code; > + > + switch (trip) { > + case TSENS_TRIP_STAGE0: > + if (!(reg_cntl & TSENS_LOWER_STATUS_CLR)) { > + hi_code = thresh >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT; > + break; > + } > + /* else fall through */ > + case TSENS_TRIP_STAGE1: > + if (!(reg_cntl & TSENS_UPPER_STATUS_CLR)) { > + hi_code = thresh >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT; > + break; > + } > + /* else fall through */ > + case TSENS_TRIP_STAGE2: > + if (!(reg_cntl & TSENS_MAX_STATUS_MASK)) { > + hi_code = thresh >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT; > + break; > + } > + /* else fall through */ > + case TSENS_TRIP_STAGE3: > + default: > + hi_code = TSENS_THRESHOLD_MAX_CODE; > + break; > + } > + > + return hi_code & TSENS_THRESHOLD_MAX_CODE; > +} > + > +static u32 tsens_lo_code(int trip, u32 reg_cntl, u32 thresh) > +{ > + u32 lo_code; > + > + switch (trip) { > + case TSENS_TRIP_STAGE3: > + if (!(reg_cntl & TSENS_UPPER_STATUS_CLR)) { > + lo_code = thresh >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT; > + break; > + } > + /* else fall through */ > + case TSENS_TRIP_STAGE2: > + if (!(reg_cntl & TSENS_LOWER_STATUS_CLR)) { > + lo_code = thresh >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT; > + break; > + } > + /* else fall through */ > + case TSENS_TRIP_STAGE1: > + if (!(reg_cntl & TSENS_MIN_STATUS_MASK)) { > + lo_code = thresh >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT; > + break; > + } > + /* else fall through */ > + case TSENS_TRIP_STAGE0: > + default: > + lo_code = TSENS_THRESHOLD_MIN_CODE; > + break; > + } > + > + return lo_code & TSENS_THRESHOLD_MAX_CODE; > +} > + > +static int tsens_tz_set_trip_temp(struct tsens_sensor *tm_sensor, > + int trip, unsigned long temp) > +{ > + struct tsens_device *tmdev = tm_sensor->tmdev; > + struct regmap_field *status = tmdev->status_field; > + u32 thresh, reg_cntl, mask = TSENS_THRESHOLD_MAX_CODE; > + u32 code, hi_code, lo_code, code_err_chk; > + > + code_err_chk = code = tsens_tz_mdegC_to_code(temp, tm_sensor); > + > + regmap_field_read(status, ®_cntl); > + regmap_read(tmdev->map, TSENS_THRESHOLD_ADDR, &thresh); > + > + switch (trip) { > + case TSENS_TRIP_STAGE3: > + code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT; > + mask <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT; > + break; > + case TSENS_TRIP_STAGE2: > + code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT; > + mask <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT; > + break; > + case TSENS_TRIP_STAGE1: > + code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT; > + mask <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT; > + break; > + case TSENS_TRIP_STAGE0: > + code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT; > + mask <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT; > + break; > + default: > + return -EINVAL; > + } > + > + hi_code = tsens_hi_code(trip, reg_cntl, thresh); > + lo_code = tsens_lo_code(trip, reg_cntl, thresh); > + > + if (code_err_chk < lo_code || code_err_chk > hi_code) > + return -EINVAL; > + > + regmap_update_bits(tmdev->map, TSENS_THRESHOLD_ADDR, mask, code); > + > + return 0; > +} > + > +static int tsens_set_trips(void *_sensor, long low, long high) > +{ > + struct tsens_sensor *tm_sensor = _sensor; > + > + tsens_print_trip_temp(tm_sensor); > + > + if (tsens_tz_set_trip_temp(tm_sensor, TSENS_TRIP_STAGE2, high)) > + return -EINVAL; > + > + if (tsens_tz_set_trip_temp(tm_sensor, TSENS_TRIP_STAGE1, low)) > + return -EINVAL; > + > + return 0; > +} > +#endif > + > +static void tsens_scheduler_fn(struct work_struct *work) > +{ > + struct tsens_device *tmdev; > + struct regmap_field *status; > + unsigned int threshold, threshold_low, i, code, bits, mask = 0; > + unsigned long sensor; > + bool upper_th_x, lower_th_x; > + > + tmdev = container_of(work, struct tsens_device, tsens_work); > + status = tmdev->status_field; > + > + regmap_field_update_bits(status, > + TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR, > + TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR); > + > + regmap_read(tmdev->map, TSENS_THRESHOLD_ADDR, &threshold); > + threshold_low = threshold >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT; > + threshold_low &= TSENS_THRESHOLD_MAX_CODE; > + threshold = threshold >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT; > + threshold &= TSENS_THRESHOLD_MAX_CODE; > + > + regmap_read(tmdev->map, TSENS_CNTL_ADDR, &bits); > + sensor = bits; > + sensor >>= TSENS_SENSOR0_SHIFT; > + for_each_set_bit(i, &sensor, tmdev->num_sensors) { > + regmap_read(tmdev->map, tmdev->sensor[i].status, &code); > + upper_th_x = code >= threshold; > + lower_th_x = code <= threshold_low; > + > + if (upper_th_x) > + mask |= TSENS_UPPER_STATUS_CLR; > + > + if (lower_th_x) > + mask |= TSENS_LOWER_STATUS_CLR; > + > +#ifdef THERMAL_TSENS8960_HWTRIPS > + if (upper_th_x || lower_th_x) { > + dev_info(tsens_dev, > + "Threshold reached for sensor(%d)\n", i); > + thermal_zone_device_update(tmdev->sensor[i].tz_dev); > + } > +#endif > + } > + > + regmap_field_update_bits(status, > + TSENS_UPPER_STATUS_CLR | TSENS_LOWER_STATUS_CLR, mask); > +} > + > +static irqreturn_t tsens_isr(int irq, void *data) > +{ > + schedule_work(data); > + return IRQ_HANDLED; > +} > + > +#ifdef CONFIG_PM > +static int tsens_suspend(struct device *dev) > +{ > + int i; > + struct tsens_device *tmdev = dev_get_drvdata(dev); > + struct regmap *map = tmdev->map; > + > + regmap_read(map, TSENS_THRESHOLD_ADDR, &tmdev->pm_tsens_thr_data); > + regmap_read(map, TSENS_CNTL_ADDR, &tmdev->pm_tsens_cntl); > + regmap_update_bits(map, TSENS_CNTL_ADDR, > + TSENS_8960_SLP_CLK_ENA | TSENS_EN, 0); > + > + tmdev->prev_reading_avail = 0; > + for (i = 0; i < tmdev->num_sensors; i++) > + tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED; > + > + return 0; > +} > + > +static int tsens_resume(struct device *dev) > +{ > + int i; > + unsigned long reg_cntl; > + struct tsens_device *tmdev = dev_get_drvdata(dev); > + struct regmap *map = tmdev->map; > + > + regmap_update_bits(map, TSENS_CNTL_ADDR, TSENS_SW_RST, TSENS_SW_RST); > + regmap_field_update_bits(tmdev->status_field, > + TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK, > + TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK); > + > + if (tmdev->num_sensors > 1) > + regmap_update_bits(map, TSENS_8960_CONFIG_ADDR, > + TSENS_8960_CONFIG_MASK, > + TSENS_8960_CONFIG); > + > + regmap_write(map, TSENS_THRESHOLD_ADDR, tmdev->pm_tsens_thr_data); > + regmap_write(map, TSENS_CNTL_ADDR, tmdev->pm_tsens_cntl); > + > + reg_cntl = tmdev->pm_tsens_cntl; > + reg_cntl >>= TSENS_SENSOR0_SHIFT; > + for_each_set_bit(i, ®_cntl, tmdev->num_sensors) > + tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED; > + > + return 0; > +} > + > +static const struct dev_pm_ops tsens_pm_ops = { > + .suspend = tsens_suspend, > + .resume = tsens_resume, > +}; > +#endif > + > +static void tsens_disable_mode(const struct tsens_device *tmdev) > +{ > + u32 reg_cntl; > + u32 mask; > + > + mask = GENMASK(tmdev->num_sensors - 1, 0); > + mask <<= TSENS_SENSOR0_SHIFT; > + mask |= TSENS_EN; > + > + regmap_read(tmdev->map, TSENS_CNTL_ADDR, ®_cntl); > + reg_cntl &= ~mask; > + if (tmdev->num_sensors > 1) > + reg_cntl &= ~TSENS_8960_SLP_CLK_ENA; > + else > + reg_cntl &= ~TSENS_8660_SLP_CLK_ENA; > + regmap_write(tmdev->map, TSENS_CNTL_ADDR, reg_cntl); > +} > + > +static void tsens_hw_init(struct tsens_device *tmdev) > +{ > + u32 reg_cntl, reg_thr; > + > + reg_cntl = TSENS_SW_RST; > + regmap_update_bits(tmdev->map, TSENS_CNTL_ADDR, TSENS_SW_RST, reg_cntl); > + > + if (tmdev->num_sensors > 1) { > + reg_cntl |= TSENS_8960_SLP_CLK_ENA | > + (TSENS_MEASURE_PERIOD << 18); Can these magic shift values go some where in defines.? > + reg_cntl &= ~TSENS_SW_RST; > + regmap_update_bits(tmdev->map, TSENS_8960_CONFIG_ADDR, > + TSENS_8960_CONFIG_MASK, TSENS_8960_CONFIG); > + } else { > + reg_cntl |= TSENS_8660_SLP_CLK_ENA | > + (TSENS_MEASURE_PERIOD << 16); > + reg_cntl &= ~TSENS_8660_CONFIG_MASK; > + reg_cntl |= TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT; > + } > + > + reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << TSENS_SENSOR0_SHIFT; > + regmap_write(tmdev->map, TSENS_CNTL_ADDR, reg_cntl); > + > + regmap_field_update_bits(tmdev->status_field, > + TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR | > + TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK, > + TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR | > + TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK); > + > + reg_cntl |= TSENS_EN; > + regmap_write(tmdev->map, TSENS_CNTL_ADDR, reg_cntl); > + > + reg_thr = (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) | > + (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) | > + (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) | > + (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT); > + regmap_write(tmdev->map, TSENS_THRESHOLD_ADDR, reg_thr); > +} > + ... > +static int > +tsens_calib_sensors8960(struct tsens_device *tmdev, struct regmap *map) > +{ > + int i; > + u32 temp_data[TSENS_MAX_SENSORS]; > + u8 *byte_data; > + u32 fuse, redun, num_read; > + struct tsens_sensor *s = tmdev->sensor; > + > + fuse = tmdev->calib_offset; > + redun = tmdev->backup_calib_offset; > + > + /** > + * syscon regmap is 32-bit data, but calibration data is 8-bit. > + * read 4 bytes from regmap in a loop and then extract bytes seprately > + */ > + It looks like workaround for the problem in syscon driver. Please use this patch to fix it. --------------------->cut<---------------------- From c50ea9c1ac61d73b1edcbc5469614cdc6655a38c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 26 Jan 2015 07:30:25 +0000 Subject: [RFC PATCH 1/2] WIP: mfd: syscon: Add register stride to DT bindings. This patch adds register stride to dt bindings so that the consumers of the syscon could change it to there need. One of the the use case for this feature is Qualcomm qfprom which needs a byte access to regmap returned from syscon. Signed-off-by: Srinivas Kandagatla --- Documentation/devicetree/bindings/mfd/syscon.txt | 3 +++ drivers/mfd/syscon.c | 9 +++++++++ 2 files changed, 12 insertions(+) if (!of_device_is_compatible(np, "syscon")) @@ -69,6 +70,14 @@ static struct syscon *of_syscon_register(struct device_node *np) else if (of_property_read_bool(np, "little-endian")) syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE; + if (!of_property_read_u32(np, "stride", &stride)) { + if (stride > 4) + stride = 4; + + syscon_config.reg_stride = stride; + syscon_config.val_bits = 8 * stride; + } + regmap = regmap_init_mmio(NULL, base, &syscon_config); if (IS_ERR(regmap)) { pr_err("regmap init failed\n"); diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt index fe8150b..7f06ec1 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.txt +++ b/Documentation/devicetree/bindings/mfd/syscon.txt @@ -13,6 +13,9 @@ Required properties: - compatible: Should contain "syscon". - reg: the register region can be accessed from syscon +Optional properties: +- stride : register address stride in bytes. + Examples: gpr: iomuxc-gpr@020e0000 { compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 176bf0f..98769d5 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -48,6 +48,7 @@ static struct syscon *of_syscon_register(struct device_node *np) struct regmap *regmap; void __iomem *base; int ret; + u32 stride; struct regmap_config syscon_config = syscon_regmap_config;