* Re: [PATCH net-next v2 2/2] drivers: net: Remove device_node checks with of_mdiobus_register()
From: Grygorii Strashko @ 2018-05-16 0:01 UTC (permalink / raw)
To: Florian Fainelli, netdev
Cc: Andrew Lunn, Vivien Didelot, David S. Miller, Nicolas Ferre,
Fugang Duan, Sergei Shtylyov, Giuseppe Cavallaro,
Alexandre Torgue, Jose Abreu, Woojung Huh,
Microchip Linux Driver Support, Rob Herring, Frank Rowand,
Antoine Tenart, Tobias Jordan, Russell King, Geert Uytterhoeven,
Thomas
In-Reply-To: <20180515235619.27773-3-f.fainelli@gmail.com>
On 05/15/2018 06:56 PM, Florian Fainelli wrote:
> A number of drivers have the following pattern:
>
> if (np)
> of_mdiobus_register()
> else
> mdiobus_register()
>
> which the implementation of of_mdiobus_register() now takes care of.
> Remove that pattern in drivers that strictly adhere to it.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> drivers/net/dsa/bcm_sf2.c | 8 ++------
> drivers/net/dsa/mv88e6xxx/chip.c | 5 +----
> drivers/net/ethernet/cadence/macb_main.c | 12 +++---------
> drivers/net/ethernet/freescale/fec_main.c | 8 ++------
> drivers/net/ethernet/marvell/mvmdio.c | 5 +----
> drivers/net/ethernet/renesas/sh_eth.c | 11 +++--------
> drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 5 +----
> drivers/net/ethernet/ti/davinci_mdio.c | 8 +++-----
for drivers/net/ethernet/ti/davinci_mdio.c:
Reviewed-by: Grygorii Strashko <grygorii.strashko@ti.com>
> drivers/net/phy/mdio-gpio.c | 6 +-----
> drivers/net/phy/mdio-mscc-miim.c | 6 +-----
> drivers/net/usb/lan78xx.c | 7 ++-----
> 11 files changed, 20 insertions(+), 61 deletions(-)
--
regards,
-grygorii
^ permalink raw reply
* Re: [PATCH 2/2] iio: adc: Add Qualcomm SPMI PMIC5 ADC driver
From: Siddartha Mohanadoss @ 2018-05-16 0:14 UTC (permalink / raw)
To: Jonathan Cameron
Cc: linux-iio, linux-arm-msm, devicetree, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, Rob Herring, cdevired,
rphani, sivaa
In-Reply-To: <20180512115652.6ad8413b@archlinux>
Hi,
On 05/12/2018 03:56 AM, Jonathan Cameron wrote:
> On Tue, 8 May 2018 14:38:56 -0700
> Siddartha Mohanadoss <smohanad@codeaurora.org> wrote:
>
>> This patch adds support for Qualcomm SPMI PMIC5 family
>> of ADC driver that supports hardware based offset and
>> gain compensation. The ADC peripheral can measure both
>> voltage and current channels whose input signal is
>> connected to the PMIC.
>>
>> The register set and configuration has been refreshed
>> compared to the prior Qualcomm PMIC ADC family. Register
>> ADC5 as part of the IIO framework.
>>
>> Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
> Various minor comments inline.
>
> Jonathan
Thanks for the review.
>
>> ---
>> drivers/iio/adc/Kconfig | 18 +
>> drivers/iio/adc/Makefile | 1 +
>> drivers/iio/adc/qcom-spmi-adc5.c | 818 +++++++++++++++++++++++++++++++
>> drivers/iio/adc/qcom-vadc-common.c | 241 +++++++++
>> drivers/iio/adc/qcom-vadc-common.h | 51 ++
>> include/dt-bindings/iio/qcom,spmi-vadc.h | 115 ++++-
>> 6 files changed, 1243 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/iio/adc/qcom-spmi-adc5.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 15606f2..ba861a1 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -567,6 +567,24 @@ config QCOM_PM8XXX_XOADC
>> To compile this driver as a module, choose M here: the module
>> will be called qcom-pm8xxx-xoadc.
>>
>> +config QCOM_SPMI_ADC5
>> + tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC"
>> + depends on SPMI
>> + select REGMAP_SPMI
>> + select QCOM_VADC_COMMON
>> + help
>> + This is the IIO Voltage PMIC5 ADC driver for Qualcomm Technologies Inc.
>> +
>> + The driver supports multiple channels read. The ADC is a 16-bit
>> + sigma-delta ADC. The hardware supports calibrated results for
>> + conversion requests and clients include reading voltage phone
>> + power, on board system thermistors connected to the PMIC ADC,
>> + PMIC die temperature, charger temperature, battery current, USB voltage
>> + input, voltage signals connected to supported PMIC GPIO inputs.
>> +
>> + To compile this driver as a module, choose M here: the module will
>> + be called qcom-spmi-adc5.
>> +
>> config QCOM_SPMI_IADC
>> tristate "Qualcomm SPMI PMIC current ADC"
>> depends on SPMI
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 28a9423..30ceb65 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -55,6 +55,7 @@ obj-$(CONFIG_NAU7802) += nau7802.o
>> obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
>> obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
>> obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
>> +obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
>> obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
>> obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
>> obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
>> diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c
>> new file mode 100644
>> index 0000000..e6bc584
>> --- /dev/null
>> +++ b/drivers/iio/adc/qcom-spmi-adc5.c
>> @@ -0,0 +1,818 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
> Don't normally have both SPDX and a licence statement...
Ok. Will remove SPDX.
>
>> + * Copyright (c) 2018, The Linux Foundation. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/bitops.h>
>> +#include <linux/completion.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/math64.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/slab.h>
>> +#include <linux/log2.h>
>> +
>> +#include <dt-bindings/iio/qcom,spmi-vadc.h>
>> +
>> +#include "qcom-vadc-common.h"
>> +
>> +#define ADC_USR_STATUS1 0x8
> I'd prefer a more unique prefix on these. Even ADC5 as you
> have used elsewhere would be an improvement an cut down
> on potential clashes some tiem in teh future.
Ok. Will prefix with defines and functions with adc5.
>
>> +#define ADC_USR_STATUS1_REQ_STS BIT(1)
>> +#define ADC_USR_STATUS1_EOC BIT(0)
>> +#define ADC_USR_STATUS1_REQ_STS_EOC_MASK 0x3
>> +
>> +#define ADC_USR_STATUS2 0x9
>> +#define ADC_USR_STATUS2_CONV_SEQ_MASK 0x70
>> +#define ADC_USR_STATUS2_CONV_SEQ_MASK_SHIFT 0x5
>> +
>> +#define ADC_USR_IBAT_MEAS 0xf
>> +#define ADC_USR_IBAT_MEAS_SUPPORTED BIT(0)
>> +
>> +#define ADC_USR_DIG_PARAM 0x42
>> +#define ADC_USR_DIG_PARAM_CAL_VAL BIT(6)
>> +#define ADC_USR_DIG_PARAM_CAL_VAL_SHIFT 6
>> +#define ADC_USR_DIG_PARAM_CAL_SEL 0x30
>> +#define ADC_USR_DIG_PARAM_CAL_SEL_SHIFT 4
>> +#define ADC_USR_DIG_PARAM_DEC_RATIO_SEL 0xc
>> +#define ADC_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT 2
>> +
>> +#define ADC_USR_FAST_AVG_CTL 0x43
>> +#define ADC_USR_FAST_AVG_CTL_EN BIT(7)
>> +#define ADC_USR_FAST_AVG_CTL_SAMPLES_MASK 0x7
>> +
>> +#define ADC_USR_CH_SEL_CTL 0x44
>> +
>> +#define ADC_USR_DELAY_CTL 0x45
>> +#define ADC_USR_HW_SETTLE_DELAY_MASK 0xf
>> +
>> +#define ADC_USR_EN_CTL1 0x46
>> +#define ADC_USR_EN_CTL1_ADC_EN BIT(7)
>> +
>> +#define ADC_USR_CONV_REQ 0x47
>> +#define ADC_USR_CONV_REQ_REQ BIT(7)
>> +
>> +#define ADC_USR_DATA0 0x50
>> +
>> +#define ADC_USR_DATA1 0x51
>> +
>> +#define ADC_USR_IBAT_DATA0 0x52
>> +
>> +#define ADC_USR_IBAT_DATA1 0x53
>> +
>> +/*
>> + * Conversion time varies based on the decimation, clock rate, fast average
>> + * samples and measurements queued across different VADC peripherals.
>> + * Set the timeout to a max of 100ms.
>> + */
>> +#define ADC_CONV_TIME_MIN_US 263
>> +#define ADC_CONV_TIME_MAX_US 264
>> +#define ADC_CONV_TIME_RETRY 400
>> +#define ADC_CONV_TIMEOUT msecs_to_jiffies(100)
>> +
>> +enum adc_cal_method {
>> + ADC_NO_CAL = 0,
>> + ADC_RATIOMETRIC_CAL,
>> + ADC_ABSOLUTE_CAL
>> +};
>> +
>> +enum adc_cal_val {
>> + ADC_TIMER_CAL = 0,
>> + ADC_NEW_CAL
>> +};
>> +
>> +/**
>> + * struct adc_channel_prop - ADC channel property.
>> + * @channel: channel number, refer to the channel list.
>> + * @cal_method: calibration method.
>> + * @cal_val: calibration value
>> + * @decimation: sampling rate supported for the channel.
>> + * @prescale: channel scaling performed on the input signal.
>> + * @hw_settle_time: the time between AMUX being configured and the
>> + * start of conversion.
>> + * @avg_samples: ability to provide single result from the ADC
>> + * that is an average of multiple measurements.
>> + * @scale_fn_type: Represents the scaling function to convert voltage
>> + * physical units desired by the client for the channel.
>> + * @datasheet_name: Channel name used in device tree.
>> + */
>> +struct adc_channel_prop {
>> + unsigned int channel;
>> + enum adc_cal_method cal_method;
>> + enum adc_cal_val cal_val;
>> + unsigned int decimation;
>> + unsigned int prescale;
>> + unsigned int hw_settle_time;
>> + unsigned int avg_samples;
>> + enum vadc_scale_fn_type scale_fn_type;
>> + const char *datasheet_name;
>> +};
>> +
>> +/**
>> + * struct adc_chip - ADC private structure.
>> + * @regmap: pointer to struct regmap.
>> + * @dev: pointer to struct device.
> The two above aren't really all that informative, anything
> more relevant you could put?
Ok.
>
>> + * @base: base address for the ADC peripheral.
>> + * @nchannels: number of ADC channels.
>> + * @chan_props: array of ADC channel properties.
>> + * @iio_chans: array of IIO channels specification.
>> + * @poll_eoc: use polling instead of interrupt.
>> + * @complete: ADC result notification after interrupt is received.
>> + * @lock: ADC lock for access to the peripheral.
>> + * @data: software configuration data.
>> + */
>> +struct adc_chip {
>> + struct regmap *regmap;
>> + struct device *dev;
>> + u16 base;
>> + unsigned int nchannels;
>> + struct adc_channel_prop *chan_props;
>> + struct iio_chan_spec *iio_chans;
>> + bool poll_eoc;
>> + struct completion complete;
>> + struct mutex lock;
>> + const struct adc_data *data;
>> +};
>> +
>> +static const struct vadc_prescale_ratio adc_prescale_ratios[] = {
>> + {.num = 1, .den = 1},
>> + {.num = 1, .den = 3},
>> + {.num = 1, .den = 4},
>> + {.num = 1, .den = 6},
>> + {.num = 1, .den = 20},
>> + {.num = 1, .den = 8},
>> + {.num = 10, .den = 81},
>> + {.num = 1, .den = 10},
>> + {.num = 1, .den = 16}
>> +};
>> +
>> +static int adc_read(struct adc_chip *adc, u16 offset, u8 *data, int len)
>> +{
>> + return regmap_bulk_read(adc->regmap, adc->base + offset, data, len);
>> +}
>> +
>> +static int adc_write(struct adc_chip *adc, u16 offset, u8 *data, int len)
>> +{
>> + return regmap_bulk_write(adc->regmap, adc->base + offset, data, len);
>> +}
>> +
>> +static int adc_prescaling_from_dt(u32 num, u32 den)
>> +{
>> + unsigned int pre;
>> +
>> + for (pre = 0; pre < ARRAY_SIZE(adc_prescale_ratios); pre++)
>> + if (adc_prescale_ratios[pre].num == num &&
>> + adc_prescale_ratios[pre].den == den)
>> + break;
>> +
>> + if (pre == ARRAY_SIZE(adc_prescale_ratios))
>> + return -EINVAL;
>> +
>> + return pre;
>> +}
>> +
>> +static int adc_hw_settle_time_from_dt(u32 value,
>> + const unsigned int *hw_settle)
>> +{
>> + uint32_t i;
>> +
>> + for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) {
>> + if (value == hw_settle[i])
>> + return i;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static int adc_avg_samples_from_dt(u32 value)
>> +{
>> + if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX)
>> + return -EINVAL;
>> +
>> + return __ffs64(value);
>> +}
>> +
>> +static int adc_read_current_data(struct adc_chip *adc, u16 *data)
>> +{
>> + int ret;
>> + u8 rslt_lsb = 0, rslt_msb = 0;
>> +
>> + ret = adc_read(adc, ADC_USR_IBAT_DATA0, &rslt_lsb, 1);
>> + if (ret)
>> + return ret;
>> +
>> + ret = adc_read(adc, ADC_USR_IBAT_DATA1, &rslt_msb, 1);
>> + if (ret)
>> + return ret;
>> +
>> + *data = (rslt_msb << 8) | rslt_lsb;
>> +
>> + if (*data == ADC_USR_DATA_CHECK) {
>> + pr_err("Invalid data:0x%x\n", *data);
>> + return -EINVAL;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int adc_read_voltage_data(struct adc_chip *adc, u16 *data)
>> +{
>> + int ret;
>> + u8 rslt_lsb = 0, rslt_msb = 0;
> Seems odd that you need to assign these for any path?
Sure. Will fix this.
>
>> +
>> + ret = adc_read(adc, ADC_USR_DATA0, &rslt_lsb, 1);
>> + if (ret)
>> + return ret;
>> +
>> + ret = adc_read(adc, ADC_USR_DATA1, &rslt_msb, 1);
>> + if (ret)
>> + return ret;
>> +
>> + *data = (rslt_msb << 8) | rslt_lsb;
>> +
>> + if (*data == ADC_USR_DATA_CHECK) {
>> + pr_err("Invalid data:0x%x\n", *data);
>> + return -EINVAL;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static int adc_poll_wait_eoc(struct adc_chip *adc)
>> +{
>> + unsigned int count, retry;
>> + u8 status1;
>> + int ret;
>> +
>> + retry = ADC_CONV_TIME_RETRY;
> unsigned int retry = ADC_CONV_TIME_RETRY;
Ok.
>> +
>> + for (count = 0; count < retry; count++) {
>> + ret = adc_read(adc, ADC_USR_STATUS1, &status1, 1);
>> + if (ret)
>> + return ret;
>> +
>> + status1 &= ADC_USR_STATUS1_REQ_STS_EOC_MASK;
>> + if (status1 == ADC_USR_STATUS1_EOC)
>> + return 0;
>> + usleep_range(ADC_CONV_TIME_MIN_US, ADC_CONV_TIME_MAX_US);
>> + }
>> +
>> + return -ETIMEDOUT;
>> +}
>> +
>> +static void adc_update_dig_param(struct adc_chip *adc,
>> + struct adc_channel_prop *prop, u8 *data)
>> +{
>> + /* Update calibration value */
>> + *data &= ~ADC_USR_DIG_PARAM_CAL_VAL;
>> + *data |= (prop->cal_val << ADC_USR_DIG_PARAM_CAL_VAL_SHIFT);
>> +
>> + /* Update calibration select */
>> + *data &= ~ADC_USR_DIG_PARAM_CAL_SEL;
>> + *data |= (prop->cal_method << ADC_USR_DIG_PARAM_CAL_SEL_SHIFT);
>> +
>> + /* Update decimation ratio select */
>> + *data &= ~ADC_USR_DIG_PARAM_DEC_RATIO_SEL;
>> + *data |= (prop->decimation << ADC_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT);
>> +}
>> +
>> +static int adc_configure(struct adc_chip *adc,
>> + struct adc_channel_prop *prop)
>> +{
>> + int ret;
>> + u8 buf[6];
>> +
>> + /* Read registers 0x42 through 0x46 */
>> + ret = adc_read(adc, ADC_USR_DIG_PARAM, buf, 6);
>> + if (ret < 0)
>> + return ret;
>> +
>> + /* Digital param selection */
>> + adc_update_dig_param(adc, prop, &buf[0]);
>> +
>> + /* Update fast average sample value */
>> + buf[1] &= (u8) ~ADC_USR_FAST_AVG_CTL_SAMPLES_MASK;
>> + buf[1] |= prop->avg_samples;
>> +
>> + /* Select ADC channel */
>> + buf[2] = prop->channel;
>> +
>> + /* Select HW settle delay for channel */
>> + buf[3] &= (u8) ~ADC_USR_HW_SETTLE_DELAY_MASK;
>> + buf[3] |= prop->hw_settle_time;
>> +
>> + /* Select ADC enable */
>> + buf[4] |= ADC_USR_EN_CTL1_ADC_EN;
>> +
>> + /* Select CONV request */
>> + buf[5] |= ADC_USR_CONV_REQ_REQ;
>> +
>> + if (!adc->poll_eoc)
>> + reinit_completion(&adc->complete);
>> +
>> + ret = adc_write(adc, ADC_USR_DIG_PARAM, buf, 6);
>> +
>> + return ret;
> return adc_write...
Ok.
>
>> +}
>> +
>> +static int adc_do_conversion(struct adc_chip *adc,
>> + struct adc_channel_prop *prop,
>> + struct iio_chan_spec const *chan,
>> + u16 *data_volt, u16 *data_cur)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&adc->lock);
>> +
>> + ret = adc_configure(adc, prop);
>> + if (ret) {
>> + pr_err("ADC configure failed with %d\n", ret);
>> + goto unlock;
>> + }
>> +
>> + if (adc->poll_eoc) {
>> + ret = adc_poll_wait_eoc(adc);
>> + if (ret < 0) {
>> + pr_err("EOC bit not set\n");
>> + goto unlock;
>> + }
>> + } else {
>> + ret = wait_for_completion_timeout(&adc->complete,
>> + ADC_CONV_TIMEOUT);
>> + if (!ret) {
>> + pr_debug("Did not get completion timeout.\n");
>> + ret = adc_poll_wait_eoc(adc);
>> + if (ret < 0) {
>> + pr_err("EOC bit not set\n");
>> + goto unlock;
>> + }
>> + }
>> + }
>> +
>> + if ((chan->type == IIO_VOLTAGE) || (chan->type == IIO_TEMP))
>> + ret = adc_read_voltage_data(adc, data_volt);
>> + else if (chan->type == IIO_POWER) {
>> + ret = adc_read_voltage_data(adc, data_volt);
>> + if (ret)
>> + goto unlock;
>> +
>> + ret = adc_read_current_data(adc, data_cur);
>> + }
>> +unlock:
>> + mutex_unlock(&adc->lock);
>> +
>> + return ret;
>> +}
>> +
>> +static irqreturn_t adc_isr(int irq, void *dev_id)
>> +{
>> + struct adc_chip *adc = dev_id;
>> +
>> + complete(&adc->complete);
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static int adc_of_xlate(struct iio_dev *indio_dev,
>> + const struct of_phandle_args *iiospec)
>> +{
>> + struct adc_chip *adc = iio_priv(indio_dev);
>> + int i;
>> +
>> + for (i = 0; i < adc->nchannels; i++)
>> + if (adc->chan_props[i].channel == iiospec->args[0])
>> + return i;
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static int adc_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan, int *val, int *val2,
>> + long mask)
>> +{
>> + struct adc_chip *adc = iio_priv(indio_dev);
>> + struct adc_channel_prop *prop;
>> + u16 adc_code_volt, adc_code_cur;
>> + int ret;
>> +
>> + prop = &adc->chan_props[chan->address];
>> +
>> + switch (mask) {
>> + case IIO_CHAN_INFO_PROCESSED:
>> + ret = adc_do_conversion(adc, prop, chan,
>> + &adc_code_volt, &adc_code_cur);
>> + if (ret)
>> + break;
>> +
>> + if ((chan->type == IIO_VOLTAGE) || (chan->type == IIO_TEMP))
>> + ret = qcom_vadc_hw_scale(prop->scale_fn_type,
>> + &adc_prescale_ratios[prop->prescale],
>> + adc->data,
>> + adc_code_volt, val);
>> + if (ret)
>> + break;
>> +
>> + if (chan->type == IIO_POWER) {
>> + ret = qcom_vadc_hw_scale(SCALE_HW_CALIB_DEFAULT,
>> + &adc_prescale_ratios[VADC_DEF_VBAT_PRESCALING],
>> + adc->data,
>> + adc_code_volt, val);
>> + if (ret)
>> + break;
>> +
>> + ret = qcom_vadc_hw_scale(prop->scale_fn_type,
>> + &adc_prescale_ratios[prop->prescale],
>> + adc->data,
>> + adc_code_cur, val2);
>> + if (ret)
>> + break;
>> + }
>> +
>> + if (chan->type == IIO_POWER)
>> + return IIO_VAL_INT_MULTIPLE;
>> + else
>> + return IIO_VAL_INT;
>> + case IIO_CHAN_INFO_RAW:
>> + ret = adc_do_conversion(adc, prop, chan,
>> + &adc_code_volt, &adc_code_cur);
>> + if (ret)
>> + break;
>> +
>> + *val = (int)adc_code_volt;
>> + *val2 = (int)adc_code_cur;
>> + if (chan->type == IIO_POWER)
>> + return IIO_VAL_INT_MULTIPLE;
>> + else
>> + return IIO_VAL_INT;
>> + default:
>> + ret = -EINVAL;
>> + break;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static const struct iio_info adc_info = {
>> + .read_raw = adc_read_raw,
>> + .of_xlate = adc_of_xlate,
>> +};
>> +
>> +struct adc_channels {
>> + const char *datasheet_name;
>> + unsigned int prescale_index;
>> + enum iio_chan_type type;
>> + long info_mask;
>> + enum vadc_scale_fn_type scale_fn_type;
>> +};
>> +
>> +#define ADC_CHAN(_dname, _type, _mask, _pre, _scale) \
>> + { \
>> + .datasheet_name = (_dname), \
>> + .prescale_index = _pre, \
>> + .type = _type, \
>> + .info_mask = _mask, \
>> + .scale_fn_type = _scale, \
>> + }, \
>> +
>> +#define ADC_CHAN_TEMP(_dname, _pre, _scale) \
>> + ADC_CHAN(_dname, IIO_TEMP, \
>> + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED), \
>> + _pre, _scale) \
>> +
>> +#define ADC_CHAN_VOLT(_dname, _pre, _scale) \
>> + ADC_CHAN(_dname, IIO_VOLTAGE, \
>> + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
>> + _pre, _scale) \
>> +
>> +#define ADC_CHAN_POWER(_dname, _pre, _scale) \
>> + ADC_CHAN(_dname, IIO_POWER, \
>> + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
>> + _pre, _scale) \
>> +
>> +static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = {
>> + [ADC_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 1,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_1P25VREF] = ADC_CHAN_VOLT("vref_1p25", 1,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_VPH_PWR] = ADC_CHAN_VOLT("vph_pwr", 3,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_VBAT_SNS] = ADC_CHAN_VOLT("vbat_sns", 3,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_DIE_TEMP] = ADC_CHAN_TEMP("die_temp", 1,
>> + SCALE_HW_CALIB_PMIC_THERM)
>> + [ADC_USB_IN_I] = ADC_CHAN_VOLT("usb_in_i_uv", 1,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_USB_IN_V_16] = ADC_CHAN_VOLT("usb_in_v_div_16", 16,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_CHG_TEMP] = ADC_CHAN_TEMP("chg_temp", 1,
>> + SCALE_HW_CALIB_PM5_CHG_TEMP)
>> + /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
>> + [ADC_SBUx] = ADC_CHAN_VOLT("chg_sbux", 3,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_MID_CHG_DIV6] = ADC_CHAN_VOLT("chg_mid_chg", 6,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1,
>> + SCALE_HW_CALIB_XOTHERM)
>> + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> + [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("int_ext_isense", 1,
>> + SCALE_HW_CALIB_CUR)
>> + [ADC_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("ext_isense", 1,
>> + SCALE_HW_CALIB_CUR)
>> + [ADC_PARALLEL_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("parallel_isense", 1,
>> + SCALE_HW_CALIB_CUR)
>> + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1,
>> + SCALE_HW_CALIB_PM5_SMB_TEMP)
>> +};
>> +
>> +static const struct adc_channels adc_chans_rev2[ADC_MAX_CHANNEL] = {
>> + [ADC_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 1,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_1P25VREF] = ADC_CHAN_VOLT("vref_1p25", 1,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_VPH_PWR] = ADC_CHAN_VOLT("vph_pwr", 3,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_VBAT_SNS] = ADC_CHAN_VOLT("vbat_sns", 3,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_VCOIN] = ADC_CHAN_VOLT("vcoin", 3,
>> + SCALE_HW_CALIB_DEFAULT)
>> + [ADC_DIE_TEMP] = ADC_CHAN_TEMP("die_temp", 1,
>> + SCALE_HW_CALIB_PMIC_THERM)
>> + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> + [ADC_AMUX_THM5_PU2] = ADC_CHAN_TEMP("amux_thm5_pu2", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> + [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP)
>> +};
>> +
>> +static int adc_get_dt_channel_data(struct device *dev,
>> + struct adc_channel_prop *prop,
>> + struct device_node *node,
>> + const struct adc_data *data)
>> +{
>> + const char *name = node->name, *channel_name;
>> + u32 chan, value, varr[2];
>> + int ret;
>> +
>> + ret = of_property_read_u32(node, "reg", &chan);
>> + if (ret) {
>> + dev_err(dev, "invalid channel number %s\n", name);
>> + return ret;
>> + }
>> +
>> + if (chan > ADC_PARALLEL_ISENSE_VBAT_IDATA) {
>> + dev_err(dev, "%s invalid channel number %d\n", name, chan);
>> + return -EINVAL;
>> + }
>> +
>> + /* the channel has DT description */
>> + prop->channel = chan;
>> +
>> + channel_name = of_get_property(node,
>> + "label", NULL) ? : node->name;
>> + if (!channel_name) {
>> + pr_err("Invalid channel name\n");
>> + return -EINVAL;
>> + }
>> + prop->datasheet_name = channel_name;
>> +
>> + ret = of_property_read_u32(node, "qcom,decimation", &value);
>> + if (!ret) {
>> + ret = qcom_adc5_decimation_from_dt(value, data->decimation);
>> + if (ret < 0) {
>> + dev_err(dev, "%02x invalid decimation %d\n",
>> + chan, value);
>> + return ret;
>> + }
>> + prop->decimation = ret;
>> + } else {
>> + prop->decimation = ADC_DECIMATION_DEFAULT;
>> + }
>> +
>> + ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
>> + if (!ret) {
>> + ret = adc_prescaling_from_dt(varr[0], varr[1]);
>> + if (ret < 0) {
>> + dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
>> + chan, varr[0], varr[1]);
>> + return ret;
>> + }
>> + prop->prescale = ret;
>> + }
>> +
>> + ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
>> + if (!ret) {
>> + ret = adc_hw_settle_time_from_dt(value, data->hw_settle);
>> + if (ret < 0) {
>> + dev_err(dev, "%02x invalid hw-settle-time %d us\n",
>> + chan, value);
>> + return ret;
>> + }
>> + prop->hw_settle_time = ret;
>> + } else {
>> + prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
>> + }
>> +
>> + ret = of_property_read_u32(node, "qcom,avg-samples", &value);
>> + if (!ret) {
>> + ret = adc_avg_samples_from_dt(value);
>> + if (ret < 0) {
>> + dev_err(dev, "%02x invalid avg-samples %d\n",
>> + chan, value);
>> + return ret;
>> + }
>> + prop->avg_samples = ret;
>> + } else {
>> + prop->avg_samples = VADC_DEF_AVG_SAMPLES;
>> + }
>> +
>> + if (of_property_read_bool(node, "qcom,ratiometric"))
>> + prop->cal_method = ADC_RATIOMETRIC_CAL;
>> + else
>> + prop->cal_method = ADC_ABSOLUTE_CAL;
>> +
>> + dev_dbg(dev, "%02x name %s\n", chan, name);
>> +
>> + return 0;
>> +}
>> +
>> +const struct adc_data data_pmic5 = {
>> + .full_scale_code_volt = 0x70e4,
>> + .full_scale_code_cur = 10000,
> Odd hex / decimal mix.
Agree. Will keep it as hex format for the two above full scale code values.
>
>> + .adc_chans = adc_chans_pmic5,
>> + .decimation = (unsigned int []) {250, 420, 840},
>> + .hw_settle = (unsigned int []) {15, 100, 200, 300, 400, 500, 600, 700,
>> + 800, 900, 1, 2, 4, 6, 8, 10},
>> +};
>> +
>> +const struct adc_data data_pmic_rev2 = {
>> + .full_scale_code_volt = 0x4000,
>> + .full_scale_code_cur = 0x1800,
>> + .adc_chans = adc_chans_rev2,
>> + .decimation = (unsigned int []) {256, 512, 1024},
> As I mention further down I'd rather see these given a specific length so
> that we ensure the numbers are consistent with those used in the relevant
> for loops. Right now we have to enforce that by review which is more
> fragile than making it explicit.
Ok. Will check.
>
>> + .hw_settle = (unsigned int []) {0, 100, 200, 300, 400, 500, 600, 700,
>> + 800, 900, 1, 2, 4, 6, 8, 10},
>> +};
>> +
>> +static const struct of_device_id adc_match_table[] = {
>> + {
>> + .compatible = "qcom,spmi-adc5",
>> + .data = &data_pmic5,
>> + },
>> + {
>> + .compatible = "qcom,spmi-adc-rev2",
>> + .data = &data_pmic_rev2,
>> + },
>> + { }
>> +};
>> +
>> +static int adc_get_dt_data(struct adc_chip *adc, struct device_node *node)
>> +{
>> + const struct adc_channels *adc_chan;
>> + struct iio_chan_spec *iio_chan;
>> + struct adc_channel_prop prop;
>> + struct device_node *child;
>> + unsigned int index = 0;
>> + const struct of_device_id *id;
>> + const struct adc_data *data;
>> + int ret;
>> +
>> + adc->nchannels = of_get_available_child_count(node);
>> + if (!adc->nchannels)
>> + return -EINVAL;
>> +
>> + adc->iio_chans = devm_kcalloc(adc->dev, adc->nchannels,
>> + sizeof(*adc->iio_chans), GFP_KERNEL);
>> + if (!adc->iio_chans)
>> + return -ENOMEM;
>> +
>> + adc->chan_props = devm_kcalloc(adc->dev, adc->nchannels,
>> + sizeof(*adc->chan_props), GFP_KERNEL);
>> + if (!adc->chan_props)
>> + return -ENOMEM;
>> +
>> + iio_chan = adc->iio_chans;
>> + id = of_match_node(adc_match_table, node);
>> + if (id)
>> + data = id->data;
>> + else
>> + data = &data_pmic5;
>> + adc->data = data;
>> +
>> + for_each_available_child_of_node(node, child) {
>> + ret = adc_get_dt_channel_data(adc->dev, &prop, child, data);
>> + if (ret) {
>> + of_node_put(child);
>> + return ret;
>> + }
>> +
>> + prop.scale_fn_type =
>> + data->adc_chans[prop.channel].scale_fn_type;
>> + adc->chan_props[index] = prop;
> It seems a little inconsistent to use an array access for chan_props
> and pointer arithmetic for iio_chan. I don't mind which style
> you want to use, but I can see a reason not to be consistent.
Ok. Will check.
>
>> +
>> + adc_chan = &data->adc_chans[prop.channel];
>> +
>> + iio_chan->channel = prop.channel;
>> + iio_chan->datasheet_name = prop.datasheet_name;
>> + iio_chan->extend_name = prop.datasheet_name;
>> + iio_chan->info_mask_separate = adc_chan->info_mask;
>> + iio_chan->type = adc_chan->type;
>> + iio_chan->address = index;
>> + iio_chan++;
>> + index++;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int adc_probe(struct platform_device *pdev)
>> +{
>> + struct device_node *node = pdev->dev.of_node;
>> + struct device *dev = &pdev->dev;
>> + struct iio_dev *indio_dev;
>> + struct adc_chip *adc;
>> + struct regmap *regmap;
>> + int ret, irq_eoc;
>> + u32 reg;
>> +
>> + regmap = dev_get_regmap(dev->parent, NULL);
>> + if (!regmap)
>> + return -ENODEV;
>> +
>> + ret = of_property_read_u32(node, "reg", ®);
>> + if (ret < 0)
>> + return ret;
>> +
>> + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
>> + if (!indio_dev)
>> + return -ENOMEM;
>> +
>> + adc = iio_priv(indio_dev);
>> + adc->regmap = regmap;
>> + adc->dev = dev;
>> + adc->base = reg;
>> + init_completion(&adc->complete);
>> + mutex_init(&adc->lock);
>> +
>> + ret = adc_get_dt_data(adc, node);
>> + if (ret) {
>> + pr_err("adc get dt data failed\n");
>> + return ret;
>> + }
>> +
>> + irq_eoc = platform_get_irq(pdev, 0);
>> + if (irq_eoc < 0) {
>> + if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
>> + return irq_eoc;
>> + adc->poll_eoc = true;
>> + } else {
>> + ret = devm_request_irq(dev, irq_eoc, adc_isr, 0,
>> + "pm-adc5", adc);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + indio_dev->dev.parent = dev;
>> + indio_dev->dev.of_node = node;
>> + indio_dev->name = pdev->name;
>> + indio_dev->modes = INDIO_DIRECT_MODE;
>> + indio_dev->info = &adc_info;
>> + indio_dev->channels = adc->iio_chans;
>> + indio_dev->num_channels = adc->nchannels;
>> +
>> + return devm_iio_device_register(dev, indio_dev);
>> +}
>> +
>> +static struct platform_driver adc_driver = {
>> + .driver = {
>> + .name = "qcom-spmi-adc5.c",
>> + .of_match_table = adc_match_table,
>> + },
>> + .probe = adc_probe,
>> +};
>> +module_platform_driver(adc_driver);
>> +
>> +MODULE_ALIAS("platform:qcom-spmi-adc5");
>> +MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 ADC driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c
>> index fe3d782..7a37035 100644
>> --- a/drivers/iio/adc/qcom-vadc-common.c
>> +++ b/drivers/iio/adc/qcom-vadc-common.c
>> @@ -47,6 +47,47 @@
>> {44, 125}
>> };
>>
>> +/*
>> + * Voltage to temperature table for 100k pull up for NTCG104EF104 with
>> + * 1.875V reference.
>> + */
>> +static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
>> + { 1831, -40000 },
>> + { 1814, -35000 },
>> + { 1791, -30000 },
>> + { 1761, -25000 },
>> + { 1723, -20000 },
>> + { 1675, -15000 },
>> + { 1616, -10000 },
>> + { 1545, -5000 },
>> + { 1463, 0 },
>> + { 1370, 5000 },
>> + { 1268, 10000 },
>> + { 1160, 15000 },
>> + { 1049, 20000 },
>> + { 937, 25000 },
>> + { 828, 30000 },
>> + { 726, 35000 },
>> + { 630, 40000 },
>> + { 544, 45000 },
>> + { 467, 50000 },
>> + { 399, 55000 },
>> + { 340, 60000 },
>> + { 290, 65000 },
>> + { 247, 70000 },
>> + { 209, 75000 },
>> + { 179, 80000 },
>> + { 153, 85000 },
>> + { 130, 90000 },
>> + { 112, 95000 },
>> + { 96, 100000 },
>> + { 82, 105000 },
>> + { 71, 110000 },
>> + { 62, 115000 },
>> + { 53, 120000 },
>> + { 46, 125000 },
>> +};
>> +
>> static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
>> u32 tablesize, s32 input, s64 *output)
>> {
>> @@ -191,6 +232,163 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
>> return 0;
>> }
>>
>> +static int qcom_vadc_scale_hw_calib_volt(
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_uv)
>> +{
>> + s64 voltage = 0, result = 0, adc_vdd_ref_mv = 1875;
>> +
>> + if (adc_code > VADC5_MAX_CODE)
>> + adc_code = 0;
>> +
>> + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
>> + voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
>> + voltage = div64_s64(voltage, data->full_scale_code_volt);
>> + voltage = voltage * prescale->den;
>> + result = div64_s64(voltage, prescale->num);
>> + *result_uv = result;
>> +
>> + return 0;
>> +}
>> +
>> +static int qcom_vadc_scale_hw_calib_therm(
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_mdec)
>> +{
>> + s64 voltage = 0, result = 0, adc_vdd_ref_mv = 1875;
>> + int ret;
>> +
>> + if (adc_code > VADC5_MAX_CODE)
>> + adc_code = 0;
>> +
>> + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
>> + voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
>> + voltage = div64_s64(voltage, (data->full_scale_code_volt
>> + * 1000));
>> + ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
>> + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
>> + voltage, &result);
>> + if (ret)
>> + return ret;
>> +
>> + *result_mdec = result;
>> +
>> + return 0;
>> +}
>> +
>> +static int qcom_vadc_scale_hw_calib_die_temp(
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_mdec)
>> +{
>> + s64 voltage = 0, adc_vdd_ref_mv = 1875;
>> + u64 temp; /* Temporary variable for do_div */
>> +
>> + if (adc_code > VADC5_MAX_CODE)
>> + adc_code = 0;
>> +
>> + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
>> + voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
>> + voltage = div64_s64(voltage, data->full_scale_code_volt);
>> + if (voltage > 0) {
>> + temp = voltage * prescale->den;
>> + do_div(temp, prescale->num * 2);
>> + voltage = temp;
>> + } else {
>> + voltage = 0;
>> + }
>> +
>> + voltage -= KELVINMIL_CELSIUSMIL;
>> + *result_mdec = voltage;
>> +
>> + return 0;
>> +}
>> +
>> +static int qcom_vadc_scale_hw_smb_temp(
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_mdec)
>> +{
> This is very close to the function below, can we not create a utility function
> that does both and save on a lot of code repetition?
The scaling was kept separate so if there are any updates to the scaling
equations across different PMIC chipsets, these are contained for each
channel separately. For now, i will try to merge these two functions and
it can be split later if needed.
>
>> + s64 voltage = 0, adc_vdd_ref_mv = 1875;
>> + u64 temp;
>> +
>> + if (adc_code > VADC5_MAX_CODE)
>> + adc_code = 0;
>> +
>> + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
>> + voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
>> + voltage = div64_s64(voltage, data->full_scale_code_volt);
>> + if (voltage > 0) {
>> + temp = voltage * prescale->den;
>> + temp *= 100;
>> + do_div(temp, prescale->num * PMIC5_SMB_TEMP_SCALE_FACTOR);
>> + voltage = temp;
>> + } else {
>> + voltage = 0;
>> + }
>> +
>> + voltage = PMIC5_SMB_TEMP_CONSTANT - voltage;
>> + *result_mdec = voltage;
>> +
>> + return 0;
>> +}
>> +
>> +static int qcom_vadc_scale_hw_chg5_temp(
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_mdec)
>> +{
>> + s64 voltage = 0, adc_vdd_ref_mv = 1875;
>> + u64 temp;
>> +
>> + if (adc_code > VADC5_MAX_CODE)
>> + adc_code = 0;
> That's unusual. Would normally expect to clamp or return an
> error, why does setting to 0 make sense here? Add a comment.
Will add a comment.
The normal data range is between 0V to 1.875V. On cases
where we read low voltage values, the ADC code can go beyond
this range and the scale result is incorrect so we clamp the values
for cases where the code represents a value below 0V.
>
>> +
>> + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
>> + voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
>> + voltage = div64_s64(voltage, data->full_scale_code_volt);
>> + if (voltage > 0) {
>> + temp = voltage * prescale->den;
>> + do_div(temp, prescale->num * 4);
>> + voltage = temp;
>> + } else {
>> + voltage = 0;
>> + }
>> +
>> + voltage = PMIC5_CHG_TEMP_SCALE_FACTOR - voltage;
>> + *result_mdec = voltage;
> Not sure why these last two lines aren't combined?
Will do.
>
>> +
>> + return 0;
>> +}
>> +
>> +static int qcom_adc_scale_hw_calib_cur(
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_uamps)
>> +{
>> + s64 voltage = 0, result = 0;
> Both are set in both paths, so don't give them values here.
> I would have expected sparse or similar to have picked up on this.
> Please run them on patches before sending out.
Ok.
>
>> +
> This code is 'unusual', please provide some docs on what the two options
> actually are and why they are different.
The data is provided in 2's complement format, with polarity convention
as positive current and negative current (current going into the battery).
Will add this comment as document.
>
>> + if ((adc_code & ADC_USR_DATA_CHECK) == 0) {
>> + voltage = (s64) adc_code * data->full_scale_code_cur * 1000;
>> + voltage = div64_s64(voltage, VADC5_MAX_CODE);
>> + voltage = voltage * prescale->den;
>> + result = div64_s64(voltage, prescale->num);
>> + *result_uamps = result;
>> + } else {
>> + adc_code = ~adc_code + 1;
> 2's comp negation? Followed at the end by negation - my immediate
> thought is that this would give exactly the same answer as the
> above path.. What am I missing?
The measurement data is provided in 2's complement format.
We convert the negative number to decimal, apply the scaling
factor and negative sign is placed in front of the final result.
>
>> + voltage = (s64) adc_code;
> Huh? You assign voltage then wipe it out on the next line.
>
> There is a lot of sharing between the two paths here. Only the first and last
> statements are different. Hmm. I'm torn on whether it would improve
> or hurt readability to have two if blocks (at start and end) rather than
> the bif if else you have currently.
Will add the two if blocks at the start and end.
>
>
>> + voltage = (s64) adc_code * data->full_scale_code_cur * 1000;
>> + voltage = div64_s64(voltage, VADC5_MAX_CODE);
>> + voltage = voltage * prescale->den;
>> + result = div64_s64(voltage, prescale->num);
>> + *result_uamps = -result;
> What does the local variable result give you? just assign directly.
Ok.
>
>> + }
>> +
>> + return 0;
>> +}
>> +
>> int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
>> const struct vadc_linear_graph *calib_graph,
>> const struct vadc_prescale_ratio *prescale,
>> @@ -221,6 +419,37 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
>> }
>> EXPORT_SYMBOL(qcom_vadc_scale);
>>
>> +int qcom_vadc_hw_scale(enum vadc_scale_fn_type scaletype,
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result)
>> +{
>> + switch (scaletype) {
> Superficially this feels like a case for a function pointer look up
> table. Table will be a little sparse but that shouldn't
> matter and it'll clean the code up here nicely.
Will check.
>
>> + case SCALE_HW_CALIB_DEFAULT:
>> + return qcom_vadc_scale_hw_calib_volt(prescale, data,
>> + adc_code, result);
>> + case SCALE_HW_CALIB_THERM_100K_PULLUP:
>> + case SCALE_HW_CALIB_XOTHERM:
>> + return qcom_vadc_scale_hw_calib_therm(prescale, data,
>> + adc_code, result);
>> + case SCALE_HW_CALIB_PMIC_THERM:
>> + return qcom_vadc_scale_hw_calib_die_temp(prescale, data,
>> + adc_code, result);
>> + case SCALE_HW_CALIB_CUR:
>> + return qcom_adc_scale_hw_calib_cur(prescale, data,
>> + adc_code, result);
>> + case SCALE_HW_CALIB_PM5_CHG_TEMP:
>> + return qcom_vadc_scale_hw_chg5_temp(prescale, data,
>> + adc_code, result);
>> + case SCALE_HW_CALIB_PM5_SMB_TEMP:
>> + return qcom_vadc_scale_hw_smb_temp(prescale, data,
>> + adc_code, result);
>> + default:
>> + return -EINVAL;
>> + }
>> +}
>> +EXPORT_SYMBOL(qcom_vadc_hw_scale);
>> +
>> int qcom_vadc_decimation_from_dt(u32 value)
>> {
>> if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
>> @@ -231,5 +460,17 @@ int qcom_vadc_decimation_from_dt(u32 value)
>> }
>> EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
>>
>> +int qcom_adc5_decimation_from_dt(u32 value, const unsigned int *decimation)
>> +{
>> + uint32_t i;
>> +
>> + for (i = 0; i < ADC_DECIMATION_SAMPLES_MAX; i++) {
> Hmm. I would like to see the arrays fed to this clearly using the
> same limits as here. Right now the code looks fragile to any
> new device where that number is not 3.
Will check.
>> + if (value == decimation[i])
>> + return i;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +EXPORT_SYMBOL(qcom_adc5_decimation_from_dt);
> Blank line here would help readability as the next line is not really connected
> to the previous one.
Ok.
>
>> MODULE_LICENSE("GPL v2");
>> MODULE_DESCRIPTION("Qualcomm ADC common functionality");
>> diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h
>> index 1d5354f..7391bcd 100644
>> --- a/drivers/iio/adc/qcom-vadc-common.h
>> +++ b/drivers/iio/adc/qcom-vadc-common.h
>> @@ -22,18 +22,34 @@
>> #define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
>> #define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */
>> #define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE
>> +#define VADC_DEF_VBAT_PRESCALING 1 /* 1:3 */
>>
>> #define VADC_DECIMATION_MIN 512
>> #define VADC_DECIMATION_MAX 4096
>> +#define ADC5_DECIMATION_SHORT 250
>> +#define ADC5_DECIMATION_MEDIUM 420
>> +#define ADC5_DECIMATION_LONG 840
>> +/* Default decimation - 1024 for rev2, 840 for pmic5 */
>> +#define ADC_DECIMATION_DEFAULT 2
>> +#define ADC_DECIMATION_SAMPLES_MAX 3
>>
>> #define VADC_HW_SETTLE_DELAY_MAX 10000
>> +#define VADC_HW_SETTLE_SAMPLES_MAX 16
>> #define VADC_AVG_SAMPLES_MAX 512
>> +#define ADC5_AVG_SAMPLES_MAX 16
>>
>> #define KELVINMIL_CELSIUSMIL 273150
>> +#define PMIC5_CHG_TEMP_SCALE_FACTOR 377500
>> +#define PMIC5_SMB_TEMP_CONSTANT 419400
>> +#define PMIC5_SMB_TEMP_SCALE_FACTOR 356
>>
>> #define PMI_CHG_SCALE_1 -138890
>> #define PMI_CHG_SCALE_2 391750000000LL
>>
>> +#define VADC5_MAX_CODE 0x7fff
>> +#define VADC5_FULL_SCALE_CODE 0x70e4
>> +#define ADC_USR_DATA_CHECK 0x8000
>> +
>> /**
>> * struct vadc_map_pt - Map the graph representation for ADC channel
>> * @x: Represent the ADC digitized code.
>> @@ -89,6 +105,19 @@ struct vadc_prescale_ratio {
>> * SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
>> * SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
>> * SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
>> + * SCALE_HW_CALIB_DEFAULT: Default scaling to convert raw adc code to
>> + * voltage (uV) with hardware applied offset/slope values to adc code.
>> + * SCALE_HW_CALIB_THERM_100K_PULLUP: Returns temperature in millidegC using
>> + * lookup table. The hardware applies offset/slope to adc code.
>> + * SCALE_HW_CALIB_XOTHERM: Returns XO thermistor voltage in millidegC using
>> + * 100k pullup. The hardware applies offset/slope to adc code.
>> + * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade.
>> + * The hardware applies offset/slope to adc code.
>> + * SCALE_HW_CALIB_CUR: Returns result in uA for PMIC5.
>> + * SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5
>> + * charger temperature.
>> + * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5
>> + * SMB1390 temperature.
>> */
>> enum vadc_scale_fn_type {
>> SCALE_DEFAULT = 0,
>> @@ -96,6 +125,21 @@ enum vadc_scale_fn_type {
>> SCALE_PMIC_THERM,
>> SCALE_XOTHERM,
>> SCALE_PMI_CHG_TEMP,
>> + SCALE_HW_CALIB_DEFAULT,
>> + SCALE_HW_CALIB_THERM_100K_PULLUP,
>> + SCALE_HW_CALIB_XOTHERM,
>> + SCALE_HW_CALIB_PMIC_THERM,
>> + SCALE_HW_CALIB_CUR,
>> + SCALE_HW_CALIB_PM5_CHG_TEMP,
>> + SCALE_HW_CALIB_PM5_SMB_TEMP,
>> +};
>> +
>> +struct adc_data {
>> + const u32 full_scale_code_volt;
>> + const u32 full_scale_code_cur;
>> + const struct adc_channels *adc_chans;
>> + unsigned int *decimation;
>> + unsigned int *hw_settle;
>> };
>>
>> int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
>> @@ -104,6 +148,13 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
>> bool absolute,
>> u16 adc_code, int *result_mdec);
>>
>> +int qcom_vadc_hw_scale(enum vadc_scale_fn_type scaletype,
>> + const struct vadc_prescale_ratio *prescale,
>> + const struct adc_data *data,
>> + u16 adc_code, int *result_mdec);
>> +
>> int qcom_vadc_decimation_from_dt(u32 value);
>>
>> +int qcom_adc5_decimation_from_dt(u32 value, const unsigned int *decimation);
>> +
>> #endif /* QCOM_VADC_COMMON_H */
>> diff --git a/include/dt-bindings/iio/qcom,spmi-vadc.h b/include/dt-bindings/iio/qcom,spmi-vadc.h
>> index 42121fa..4aa35de 100644
>> --- a/include/dt-bindings/iio/qcom,spmi-vadc.h
>> +++ b/include/dt-bindings/iio/qcom,spmi-vadc.h
>> @@ -1,5 +1,5 @@
>> /*
>> - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2012-2014,2018 The Linux Foundation. All rights reserved.
>> *
>> * This program is free software; you can redistribute it and/or modify
>> * it under the terms of the GNU General Public License version 2 and
>> @@ -116,4 +116,117 @@
>> #define VADC_LR_MUX10_PU1_PU2_AMUX_USB_ID 0xf9
>> #define VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM 0xfc
>>
>> +/* ADC channels for SPMI VADC5*/
> Check general comment formatting. Should be a space before the */
Ok.
>
>> +
>> +#define ADC_REF_GND 0x00
> Given these are all being added to a generic(ish) header and only
> apply to this new part, we should give them a prefix that makes this
> clear.
Will prefix it with ADC5.
>
>> +#define ADC_1P25VREF 0x01
>> +#define ADC_VREF_VADC 0x02
>> +#define ADC_VREF_VADC_DIV_3 0x82
>> +#define ADC_VPH_PWR 0x83
>> +#define ADC_VBAT_SNS 0x84
>> +#define ADC_VCOIN 0x85
>> +#define ADC_DIE_TEMP 0x06
>> +#define ADC_USB_IN_I 0x07
>> +#define ADC_USB_IN_V_16 0x08
>> +#define ADC_CHG_TEMP 0x09
>> +#define ADC_BAT_THERM 0x0a
>> +#define ADC_BAT_ID 0x0b
>> +#define ADC_XO_THERM 0x0c
>> +#define ADC_AMUX_THM1 0x0d
>> +#define ADC_AMUX_THM2 0x0e
>> +#define ADC_AMUX_THM3 0x0f
>> +#define ADC_AMUX_THM4 0x10
>> +#define ADC_AMUX_THM5 0x11
>> +#define ADC_GPIO1 0x12
>> +#define ADC_GPIO2 0x13
>> +#define ADC_GPIO3 0x14
>> +#define ADC_GPIO4 0x15
>> +#define ADC_GPIO5 0x16
>> +#define ADC_GPIO6 0x17
>> +#define ADC_GPIO7 0x18
>> +#define ADC_SBUx 0x99
>> +#define ADC_MID_CHG_DIV6 0x1e
>> +#define ADC_OFF 0xff
>> +
>> +/* 30k pull-up1 */
> I'd prefer to see the 30k value in the names.
>
> XXX_ADC_BAT_THERM_30K_PU perhaps or something like that?
Ok.
>
>> +#define ADC_BAT_THERM_PU1 0x2a
>> +#define ADC_BAT_ID_PU1 0x2b
>> +#define ADC_XO_THERM_PU1 0x2c
>> +#define ADC_AMUX_THM1_PU1 0x2d
>> +#define ADC_AMUX_THM2_PU1 0x2e
>> +#define ADC_AMUX_THM3_PU1 0x2f
>> +#define ADC_AMUX_THM4_PU1 0x30
>> +#define ADC_AMUX_THM5_PU1 0x31
>> +#define ADC_GPIO1_PU1 0x32
>> +#define ADC_GPIO2_PU1 0x33
>> +#define ADC_GPIO3_PU1 0x34
>> +#define ADC_GPIO4_PU1 0x35
>> +#define ADC_GPIO5_PU1 0x36
>> +#define ADC_GPIO6_PU1 0x37
>> +#define ADC_GPIO7_PU1 0x38
>> +#define ADC_SBUx_PU1 0x39
>> +
>> +/* 100k pull-up2 */
>> +#define ADC_BAT_THERM_PU2 0x4a
>> +#define ADC_BAT_ID_PU2 0x4b
>> +#define ADC_XO_THERM_PU2 0x4c
>> +#define ADC_AMUX_THM1_PU2 0x4d
>> +#define ADC_AMUX_THM2_PU2 0x4e
>> +#define ADC_AMUX_THM3_PU2 0x4f
>> +#define ADC_AMUX_THM4_PU2 0x50
>> +#define ADC_AMUX_THM5_PU2 0x51
>> +#define ADC_GPIO1_PU2 0x52
>> +#define ADC_GPIO2_PU2 0x53
>> +#define ADC_GPIO3_PU2 0x54
>> +#define ADC_GPIO4_PU2 0x55
>> +#define ADC_GPIO5_PU2 0x56
>> +#define ADC_GPIO6_PU2 0x57
>> +#define ADC_GPIO7_PU2 0x58
>> +#define ADC_SBUx_PU2 0x59
>> +
>> +/* 400k pull-up3 */
>> +#define ADC_BAT_THERM_PU3 0x6a
>> +#define ADC_BAT_ID_PU3 0x6b
>> +#define ADC_XO_THERM_PU3 0x6c
>> +#define ADC_AMUX_THM1_PU3 0x6d
>> +#define ADC_AMUX_THM2_PU3 0x6e
>> +#define ADC_AMUX_THM3_PU3 0x6f
>> +#define ADC_AMUX_THM4_PU3 0x70
>> +#define ADC_AMUX_THM5_PU3 0x71
>> +#define ADC_GPIO1_PU3 0x72
>> +#define ADC_GPIO2_PU3 0x73
>> +#define ADC_GPIO3_PU3 0x74
>> +#define ADC_GPIO4_PU3 0x75
>> +#define ADC_GPIO5_PU3 0x76
>> +#define ADC_GPIO6_PU3 0x77
>> +#define ADC_GPIO7_PU3 0x78
>> +#define ADC_SBUx_PU3 0x79
>> +
>> +/* 1/3 Divider */
>> +#define ADC_GPIO1_DIV3 0x92
>> +#define ADC_GPIO2_DIV3 0x93
>> +#define ADC_GPIO3_DIV3 0x94
>> +#define ADC_GPIO4_DIV3 0x95
>> +#define ADC_GPIO5_DIV3 0x96
>> +#define ADC_GPIO6_DIV3 0x97
>> +#define ADC_GPIO7_DIV3 0x98
>> +#define ADC_SBUx_DIV3 0x99
>> +
>> +/* Current and combined current/voltage channels */
>> +#define ADC_INT_EXT_ISENSE 0xa1
>> +#define ADC_PARALLEL_ISENSE 0xa5
>> +#define ADC_CUR_REPLICA_VDS 0xa7
>> +#define ADC_CUR_SENS_BATFET_VDS_OFFSET 0xa9
>> +#define ADC_CUR_SENS_REPLICA_VDS_OFFSET 0xab
>> +#define ADC_EXT_SENS_OFFSET 0xad
>> +
>> +#define ADC_INT_EXT_ISENSE_VBAT_VDATA 0xb0
>> +#define ADC_INT_EXT_ISENSE_VBAT_IDATA 0xb1
>> +#define ADC_EXT_ISENSE_VBAT_VDATA 0xb2
>> +#define ADC_EXT_ISENSE_VBAT_IDATA 0xb3
>> +#define ADC_PARALLEL_ISENSE_VBAT_VDATA 0xb4
>> +#define ADC_PARALLEL_ISENSE_VBAT_IDATA 0xb5
>> +
>> +#define ADC_MAX_CHANNEL 0xc0
>> +
>> #endif /* _DT_BINDINGS_QCOM_SPMI_VADC_H */
^ permalink raw reply
* Re: [PATCH v10 00/27] ARM: davinci: convert to common clock framework
From: David Lechner @ 2018-05-16 0:31 UTC (permalink / raw)
To: Adam Ford, Bartosz Golaszewski
Cc: linux-clk, devicetree, arm-soc, Michael Turquette, Stephen Boyd,
Rob Herring, Mark Rutland, Sekhar Nori, Kevin Hilman,
Bartosz Golaszewski, Linux Kernel Mailing List
In-Reply-To: <CAHCN7xJt=tsc2zHWu+6y_2z=+kHdaovh3TD_MJ1+UeUbTdyj8w@mail.gmail.com>
On 5/15/18 5:44 PM, Adam Ford wrote:
> On Tue, May 15, 2018 at 4:25 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>> 2018-05-14 2:40 GMT+02:00 Adam Ford <aford173@gmail.com>:
>>> On Wed, May 9, 2018 at 12:25 PM, David Lechner <david@lechnology.com> wrote:
>>>> This series converts mach-davinci to use the common clock framework.
>>>>
>>>> The series works like this, the first 3 patches fix some issues with the clock
>>>> drivers that have already been accepted into the mainline kernel.
>>>>
>>>> Then, starting with "ARM: davinci: pass clock as parameter to
>>>> davinci_timer_init()", we get the mach code ready for the switch by adding the
>>>> code needed for the new clock drivers and adding #ifndef CONFIG_COMMON_CLK
>>>> around the legacy clocks so that we can switch easily between the old and the
>>>> new.
>>>>
>>>> "ARM: davinci: switch to common clock framework" actually flips the switch
>>>> to start using the new clock drivers. Then the next 8 patches remove all
>>>> of the old clock code.
>>>>
>>>> The final four patches add device tree clock support to the one SoC that
>>>> supports it.
>>>>
>>>> This series has been tested on TI OMAP-L138 LCDK (both device tree and legacy
>>>> board file).
>>>>
>>>
>>> I am not sure if I did something wrong, but I attempted to build and I
>>> wasn't able to boot the da850-evm.dtb your repo common-clk-v11,
>>> however the legacy board file boot was OK.
>>>
>>> make davinci_all_defconfig ARCH=arm
>>> make zImage modules da850-evm.dtb ARCH=arm CROSS_COMPILE=arm-linux- -j8
>>>
>>> 3140416 bytes read in 1464 ms (2 MiB/s)
>>> 20353 bytes read in 15 ms (1.3 MiB/s)
>>> ## Flattened Device Tree blob at c0600000
>>> Booting using the fdt blob at 0xc0600000
>>> Loading Device Tree to c7e57000, end c7e5ef80 ... OK
>>>
>>> Starting kernel ...
>>>
>>> Uncompressing Linux... done, booting the kernel.
>>>
>>> (and hang)
>>>
>>> If you have some suggestions, I am try them as I get time.
>>>
>>> adam
>>>
>>
>> Runs fine on da850-lcdk and dm365-evm. I'll test the da850-evm
>> tomorrow when I'll have access to it.
>
> I set the bootargs to: bootargs=console=ttyS2,115200n8
> clk_ignore_unused root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait
It looks like you forgot earlyprintk in your bootargs.
>
> I enabled DEBUG_LL and EARLY_PRINTK, yet when it loads, I only get:
>
> ## Flattened Device Tree blob at c0600000
> Booting using the fdt blob at 0xc0600000
> Loading Device Tree to c7e57000, end c7e5ef35 ... OK
>
> Starting kernel ...
>
> Uncompressing Linux... done, booting the kernel.
>
>
> I am doing this at my home, so I don't have a debugger for the
> DA850-EVM. I am using a SOM that is an AM1808, but I vaguely remember
> something about enabling a DSP clock somewhere, but I cannot seem to
> find the e-mail. I know its counter intuitive that we'd need to
> enable a clock that runs the DSP since it doesn't exist on the AM1808,
> but I would have thought the clk_ignore_unused would have worked
> around that issue.
>
> If someone else has a DA850-EVM or suggestions, I'm willing to try
> them as I have time.
>
> adam
>>
>> Bart
^ permalink raw reply
* Re: [PATCH 10/12] platform/early: implement support for early platform drivers
From: Rob Herring @ 2018-05-16 1:06 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Sekhar Nori, Kevin Hilman, David Lechner, Michael Turquette,
Stephen Boyd, Arnd Bergmann, Greg Kroah-Hartman, Mark Rutland,
Yoshinori Sato, Rich Felker, Andy Shevchenko, Marc Zyngier,
Rafael J . Wysocki, Peter Rosin, Jiri Slaby, Thomas Gleixner,
Daniel Lezcano, Geert Uytterhoeven, Magnus Damm, Johan Hovold
In-Reply-To: <CAMRc=MdsDWb0Ve29_d=30nc1F0aVhTrG74GX=sv0iB5WycWwLw@mail.gmail.com>
On Tue, May 15, 2018 at 9:06 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> 2018-05-14 15:37 GMT+02:00 Rob Herring <robh+dt@kernel.org>:
>> On Fri, May 11, 2018 at 11:20 AM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>>> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>>>
>>> This introduces the core part of support for early platform drivers
>>> and devices.
>>>
>>
>> It looks like most of your prep patches are to separate the alloc and
>> init of platform devices because you are essentially making early
>> devices/drivers a sub-class. Maybe you could avoid doing that and
>> simplify things a bit. Comments below based on doing that...
>>
>
> My aim was to change as little as possible for everybody else while
> fixing our problem. These changes are already controversial enough
> without risky reusing of existing fields in common structures. I was
> just afraid that there are too many intricacies for it to be safe.
I don't think those intricacies would go away just by having separate
fields. Perhaps it would make things fail more explicitly. After all,
I think it needs to be a very atomic operation when a device is
switched.
>>> +/**
>>> + * struct early_platform_driver
>>> + *
>>> + * @pdrv: real platform driver associated with this early platform driver
>>> + * @list: list head for the list of early platform drivers
>>> + * @early_probe: early probe callback
>>> + */
>>> +struct early_platform_driver {
>>> + struct platform_driver pdrv;
>>> + struct list_head list;
>>
>> Couldn't you use an existing list in driver_private until you move
>> over to the normal bus infra.
>>
>
> This is something that the previous implementation did. It was quite
> unreadable, so I decided to go with a separate list.
>
>>> + int (*early_probe)(struct platform_device *);
>>
>> Just add this to platform_driver.
>>
>
> This would extend the structure for everybody else while there'll be
> very few such devices and not all systems would even require it.
>
>>> +};
>>> +
>>> +/**
>>> + * struct early_platform_device
>>> + *
>>> + * @pdev: real platform device associated with this early platform device
>>> + * @list: list head for the list of early platform devices
>>> + * @deferred: true if this device's early probe was deferred
>>> + * @deferred_drv: early platform driver with which this device was matched
>>> + */
>>> +struct early_platform_device {
>>> + struct platform_device pdev;
>>> + struct list_head list;
>>
>> Use a list in device_private?
>>
>>> + bool deferred;
>>> + struct early_platform_driver *deferred_drv;
>>
>> Can't you use the existing deferred probe list?
>>
>
> I thought about it, but I was afraid there could be some timing issues
> with that and decided against it. The early deferral also doesn't work
> in a workque, but is synchronous instead.
I didn't mean use the wq, but just the list fields. You'd still have
the early list and normal list with different list heads. If you ever
had a device wanting to be on both lists at the same time, then you've
got major problems.
Rob
^ permalink raw reply
* RE: [PATCH net-next v2 2/2] drivers: net: Remove device_node checks with of_mdiobus_register()
From: Andy Duan @ 2018-05-16 1:57 UTC (permalink / raw)
To: Florian Fainelli, netdev@vger.kernel.org
Cc: Andrew Lunn, Vivien Didelot, David S. Miller, Nicolas Ferre,
Sergei Shtylyov, Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
Grygorii Strashko, Woojung Huh, Microchip Linux Driver Support,
Rob Herring, Frank Rowand, Antoine Tenart, Tobias Jordan,
Russell King, Geert Uytterhoeven, Th
In-Reply-To: <20180515235619.27773-3-f.fainelli@gmail.com>
From: Florian Fainelli <f.fainelli@gmail.com> Sent: 2018年5月16日 7:56
> A number of drivers have the following pattern:
>
> if (np)
> of_mdiobus_register()
> else
> mdiobus_register()
>
> which the implementation of of_mdiobus_register() now takes care of.
> Remove that pattern in drivers that strictly adhere to it.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
For drivers/net/ethernet/freescale/fec_main.c:
Reviewed-by: Fugang Duan <fugang.duan@nxp.com>
> ---
> drivers/net/dsa/bcm_sf2.c | 8 ++------
> drivers/net/dsa/mv88e6xxx/chip.c | 5 +----
> drivers/net/ethernet/cadence/macb_main.c | 12 +++---------
> drivers/net/ethernet/freescale/fec_main.c | 8 ++------
> drivers/net/ethernet/marvell/mvmdio.c | 5 +----
> drivers/net/ethernet/renesas/sh_eth.c | 11 +++--------
> drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 5 +----
> drivers/net/ethernet/ti/davinci_mdio.c | 8 +++-----
> drivers/net/phy/mdio-gpio.c | 6 +-----
> drivers/net/phy/mdio-mscc-miim.c | 6 +-----
> drivers/net/usb/lan78xx.c | 7 ++-----
> 11 files changed, 20 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index
> ac621f44237a..02e8982519ce 100644
> --- a/drivers/net/dsa/bcm_sf2.c
> +++ b/drivers/net/dsa/bcm_sf2.c
> @@ -450,12 +450,8 @@ static int bcm_sf2_mdio_register(struct dsa_switch
> *ds)
> priv->slave_mii_bus->parent = ds->dev->parent;
> priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;
>
> - if (dn)
> - err = of_mdiobus_register(priv->slave_mii_bus, dn);
> - else
> - err = mdiobus_register(priv->slave_mii_bus);
> -
> - if (err)
> + err = of_mdiobus_register(priv->slave_mii_bus, dn);
> + if (err && dn)
> of_node_put(dn);
>
> return err;
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c
> b/drivers/net/dsa/mv88e6xxx/chip.c
> index b23c11d9f4b2..2bb3f03ee1cb 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -2454,10 +2454,7 @@ static int mv88e6xxx_mdio_register(struct
> mv88e6xxx_chip *chip,
> return err;
> }
>
> - if (np)
> - err = of_mdiobus_register(bus, np);
> - else
> - err = mdiobus_register(bus);
> + err = of_mdiobus_register(bus, np);
> if (err) {
> dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
> mv88e6xxx_g2_irq_mdio_free(chip, bus); diff --git
> a/drivers/net/ethernet/cadence/macb_main.c
> b/drivers/net/ethernet/cadence/macb_main.c
> index b4c9268100bb..3e93df5d4e3b 100644
> --- a/drivers/net/ethernet/cadence/macb_main.c
> +++ b/drivers/net/ethernet/cadence/macb_main.c
> @@ -591,16 +591,10 @@ static int macb_mii_init(struct macb *bp)
> dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
>
> np = bp->pdev->dev.of_node;
> + if (pdata)
> + bp->mii_bus->phy_mask = pdata->phy_mask;
>
> - if (np) {
> - err = of_mdiobus_register(bp->mii_bus, np);
> - } else {
> - if (pdata)
> - bp->mii_bus->phy_mask = pdata->phy_mask;
> -
> - err = mdiobus_register(bp->mii_bus);
> - }
> -
> + err = of_mdiobus_register(bp->mii_bus, np);
> if (err)
> goto err_out_free_mdiobus;
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c
> b/drivers/net/ethernet/freescale/fec_main.c
> index d4604bc8eb5b..f3e43db0d6cb 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -2052,13 +2052,9 @@ static int fec_enet_mii_init(struct platform_device
> *pdev)
> fep->mii_bus->parent = &pdev->dev;
>
> node = of_get_child_by_name(pdev->dev.of_node, "mdio");
> - if (node) {
> - err = of_mdiobus_register(fep->mii_bus, node);
> + err = of_mdiobus_register(fep->mii_bus, node);
> + if (node)
> of_node_put(node);
> - } else {
> - err = mdiobus_register(fep->mii_bus);
> - }
> -
> if (err)
> goto err_out_free_mdiobus;
>
> diff --git a/drivers/net/ethernet/marvell/mvmdio.c
> b/drivers/net/ethernet/marvell/mvmdio.c
> index 0495487f7b42..c5dac6bd2be4 100644
> --- a/drivers/net/ethernet/marvell/mvmdio.c
> +++ b/drivers/net/ethernet/marvell/mvmdio.c
> @@ -348,10 +348,7 @@ static int orion_mdio_probe(struct platform_device
> *pdev)
> goto out_mdio;
> }
>
> - if (pdev->dev.of_node)
> - ret = of_mdiobus_register(bus, pdev->dev.of_node);
> - else
> - ret = mdiobus_register(bus);
> + ret = of_mdiobus_register(bus, pdev->dev.of_node);
> if (ret < 0) {
> dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
> goto out_mdio;
> diff --git a/drivers/net/ethernet/renesas/sh_eth.c
> b/drivers/net/ethernet/renesas/sh_eth.c
> index 5970d9e5ddf1..8dd41e08a6c6 100644
> --- a/drivers/net/ethernet/renesas/sh_eth.c
> +++ b/drivers/net/ethernet/renesas/sh_eth.c
> @@ -3025,15 +3025,10 @@ static int sh_mdio_init(struct sh_eth_private
> *mdp,
> pdev->name, pdev->id);
>
> /* register MDIO bus */
> - if (dev->of_node) {
> - ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
> - } else {
> - if (pd->phy_irq > 0)
> - mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
> -
> - ret = mdiobus_register(mdp->mii_bus);
> - }
> + if (pd->phy_irq > 0)
> + mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
>
> + ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
> if (ret)
> goto out_free_bus;
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> index f5f37bfa1d58..5df1a608e566 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> @@ -233,10 +233,7 @@ int stmmac_mdio_register(struct net_device *ndev)
> new_bus->phy_mask = mdio_bus_data->phy_mask;
> new_bus->parent = priv->device;
>
> - if (mdio_node)
> - err = of_mdiobus_register(new_bus, mdio_node);
> - else
> - err = mdiobus_register(new_bus);
> + err = of_mdiobus_register(new_bus, mdio_node);
> if (err != 0) {
> dev_err(dev, "Cannot register the MDIO bus\n");
> goto bus_register_fail;
> diff --git a/drivers/net/ethernet/ti/davinci_mdio.c
> b/drivers/net/ethernet/ti/davinci_mdio.c
> index 98a1c97fb95e..8ac72831af05 100644
> --- a/drivers/net/ethernet/ti/davinci_mdio.c
> +++ b/drivers/net/ethernet/ti/davinci_mdio.c
> @@ -429,12 +429,10 @@ static int davinci_mdio_probe(struct
> platform_device *pdev)
> * defined to support backward compatibility with DTs which assume that
> * Davinci MDIO will always scan the bus for PHYs detection.
> */
> - if (dev->of_node && of_get_child_count(dev->of_node)) {
> + if (dev->of_node && of_get_child_count(dev->of_node))
> data->skip_scan = true;
> - ret = of_mdiobus_register(data->bus, dev->of_node);
> - } else {
> - ret = mdiobus_register(data->bus);
> - }
> +
> + ret = of_mdiobus_register(data->bus, dev->of_node);
> if (ret)
> goto bail_out;
>
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index
> b501221819e1..4e4c8daf44c3 100644
> --- a/drivers/net/phy/mdio-gpio.c
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -179,11 +179,7 @@ static int mdio_gpio_probe(struct platform_device
> *pdev)
> if (!new_bus)
> return -ENODEV;
>
> - if (pdev->dev.of_node)
> - ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
> - else
> - ret = mdiobus_register(new_bus);
> -
> + ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
> if (ret)
> mdio_gpio_bus_deinit(&pdev->dev);
>
> diff --git a/drivers/net/phy/mdio-mscc-miim.c
> b/drivers/net/phy/mdio-mscc-miim.c
> index 8c689ccfdbca..badbc99bedd3 100644
> --- a/drivers/net/phy/mdio-mscc-miim.c
> +++ b/drivers/net/phy/mdio-mscc-miim.c
> @@ -151,11 +151,7 @@ static int mscc_miim_probe(struct platform_device
> *pdev)
> }
> }
>
> - if (pdev->dev.of_node)
> - ret = of_mdiobus_register(bus, pdev->dev.of_node);
> - else
> - ret = mdiobus_register(bus);
> -
> + ret = of_mdiobus_register(bus, pdev->dev.of_node);
> if (ret < 0) {
> dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
> return ret;
> diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index
> 91761436709a..8dff87ec6d99 100644
> --- a/drivers/net/usb/lan78xx.c
> +++ b/drivers/net/usb/lan78xx.c
> @@ -1843,12 +1843,9 @@ static int lan78xx_mdio_init(struct lan78xx_net
> *dev)
> }
>
> node = of_get_child_by_name(dev->udev->dev.of_node, "mdio");
> - if (node) {
> - ret = of_mdiobus_register(dev->mdiobus, node);
> + ret = of_mdiobus_register(dev->mdiobus, node);
> + if (node)
> of_node_put(node);
> - } else {
> - ret = mdiobus_register(dev->mdiobus);
> - }
> if (ret) {
> netdev_err(dev->net, "can't register MDIO bus\n");
> goto exit1;
> --
> 2.14.1
^ permalink raw reply
* [PATCH V2] ARM: dts: imx7d: correct cpu supply name for voltage scaling
From: Anson Huang @ 2018-05-16 2:25 UTC (permalink / raw)
To: shawnguo, kernel, fabio.estevam, robh+dt, mark.rutland
Cc: Linux-imx, linux-arm-kernel, devicetree, linux-kernel
Correct CPU supply name to meet cpufreq-dt driver's
requirement for voltage scaling.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
---
changes since V1:
fix the "No newline at end of file" caused by vim editor.
arch/arm/boot/dts/imx7d-cl-som-imx7.dts | 2 +-
arch/arm/boot/dts/imx7d-nitrogen7.dts | 2 +-
arch/arm/boot/dts/imx7d-sdb.dts | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
index 7f64568..8bf365d 100644
--- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
+++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
@@ -33,7 +33,7 @@
};
&cpu0 {
- arm-supply = <&sw1a_reg>;
+ cpu-supply = <&sw1a_reg>;
};
&fec1 {
diff --git a/arch/arm/boot/dts/imx7d-nitrogen7.dts b/arch/arm/boot/dts/imx7d-nitrogen7.dts
index b8e73b4..70c53e5 100644
--- a/arch/arm/boot/dts/imx7d-nitrogen7.dts
+++ b/arch/arm/boot/dts/imx7d-nitrogen7.dts
@@ -144,7 +144,7 @@
};
&cpu0 {
- arm-supply = <&sw1a_reg>;
+ cpu-supply = <&sw1a_reg>;
};
&fec1 {
diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
index 722a45a..9408491 100644
--- a/arch/arm/boot/dts/imx7d-sdb.dts
+++ b/arch/arm/boot/dts/imx7d-sdb.dts
@@ -141,7 +141,7 @@
};
&cpu0 {
- arm-supply = <&sw1a_reg>;
+ cpu-supply = <&sw1a_reg>;
};
&ecspi3 {
--
2.7.4
^ permalink raw reply related
* [PATCH v3 0/2] usb: dwc3: support clocks and resets for DWC3 core
From: Masahiro Yamada @ 2018-05-16 2:41 UTC (permalink / raw)
To: linux-usb, Felipe Balbi
Cc: Rob Herring, Roger Quadros, Martin Blumenstingl, Masami Hiramatsu,
Jassi Brar, Kunihiko Hayashi, Masahiro Yamada, devicetree,
Felipe Balbi, linux-kernel, Rob Herring, Greg Kroah-Hartman,
Mark Rutland
In the current design of DWC3 driver,
the DT typically becomes a nested structure like follows:
dwc3-glue {
compatible = "foo,dwc3";
...
dwc3 {
compatible = "snps,dwc3";
...
};
}
The current DWC3 core (drivers/usb/dwc3/core.c) can not handle
clocks / resets at all.
The only solution we have now, is to put DWC3 core node under
the glue layer node, then add clocks and resets there.
Actually, dwc3-of-simple.c exists to handle clocks and resets.
As always for digital circuits, DWC3 core IP itself needs clock input.
This is specific to this IP. So, supporting clocks and resets in
dwc3/core.c makes sense.
In this version, the number of clocks (and names) is specific
to this IP, with clock names taken from Synopsys datasheet.
Masahiro Yamada (2):
usb: dwc3: use local copy of resource to fix-up register offset
usb: dwc3: support clocks and resets for DWC3 core
Documentation/devicetree/bindings/usb/dwc3.txt | 21 +++++
drivers/usb/dwc3/core.c | 118 +++++++++++++++++++------
drivers/usb/dwc3/core.h | 8 ++
3 files changed, 122 insertions(+), 25 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH v3 2/2] usb: dwc3: support clocks and resets for DWC3 core
From: Masahiro Yamada @ 2018-05-16 2:41 UTC (permalink / raw)
To: linux-usb, Felipe Balbi
Cc: Rob Herring, Roger Quadros, Martin Blumenstingl, Masami Hiramatsu,
Jassi Brar, Kunihiko Hayashi, Masahiro Yamada, devicetree,
Felipe Balbi, linux-kernel, Rob Herring, Greg Kroah-Hartman,
Mark Rutland
In-Reply-To: <1526438467-12470-1-git-send-email-yamada.masahiro@socionext.com>
Historically, the clocks and resets are handled on the glue layer
side instead of the DWC3 core. For simple cases, dwc3-of-simple.c
takes care of arbitrary number of clocks and resets. The DT node
structure typically looks like as follows:
dwc3-glue {
compatible = "foo,dwc3";
clocks = ...;
resets = ...;
...
dwc3 {
compatible = "snps,dwc3";
...
};
}
By supporting the clocks and the reset in the dwc3/core.c, it will
be turned into a single node:
dwc3 {
compatible = "foo,dwc3", "snps,dwc3";
clocks = ...;
resets = ...;
...
}
This commit adds the binding of clocks and resets specific to this IP.
The number of clocks should generally be the same across SoCs, it is
just some SoCs either tie clocks together or do not provide software
control of some of the clocks.
I took the clock names from the Synopsys datasheet: "ref" (ref_clk),
"bus_early" (bus_clk_early), and "suspend" (suspend_clk).
I found only one reset line in the datasheet, hence the reset-names
property is omitted.
Those clocks are required for new platforms. Enforcing the new
binding breaks existing platforms since they specify clocks (and
resets) in their glue layer node, but nothing in the core node.
I listed such exceptional cases in the DT binding. The driver
code has been relaxed to accept no clock. This change is based
on the discussion [1].
I inserted reset_control_deassert() and clk_bulk_enable() before the
first register access, i.e. dwc3_cache_hwparams().
[1] https://patchwork.kernel.org/patch/10284265/
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes in v3:
- Change 'resets' DT property to optional.
Changes in v2:
- Make clocks specific to this IP based on Synopsys datasheet
- Use clk_bulk API
- Add description to struct header
Documentation/devicetree/bindings/usb/dwc3.txt | 21 ++++++
drivers/usb/dwc3/core.c | 88 +++++++++++++++++++++++++-
drivers/usb/dwc3/core.h | 8 +++
3 files changed, 115 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 0dbd308..7f13ebe 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -7,6 +7,26 @@ Required properties:
- compatible: must be "snps,dwc3"
- reg : Address and length of the register set for the device
- interrupts: Interrupts used by the dwc3 controller.
+ - clock-names: should contain "ref", "bus_early", "suspend"
+ - clocks: list of phandle and clock specifier pairs corresponding to
+ entries in the clock-names property.
+
+Exception for clocks:
+ clocks are optional if the parent node (i.e. glue-layer) is compatible to
+ one of the following:
+ "amlogic,meson-axg-dwc3"
+ "amlogic,meson-gxl-dwc3"
+ "cavium,octeon-7130-usb-uctl"
+ "qcom,dwc3"
+ "samsung,exynos5250-dwusb3"
+ "samsung,exynos7-dwusb3"
+ "sprd,sc9860-dwc3"
+ "st,stih407-dwc3"
+ "ti,am437x-dwc3"
+ "ti,dwc3"
+ "ti,keystone-dwc3"
+ "rockchip,rk3399-dwc3"
+ "xlnx,zynqmp-dwc3"
Optional properties:
- usb-phy : array of phandle for the PHY device. The first element
@@ -15,6 +35,7 @@ Optional properties:
- phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
+ - resets: a single pair of phandle and reset specifier
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
- snps,disable_scramble_quirk: true when SW should disable data scrambling.
Only really useful for FPGA builds.
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 8e66edd..0380a85 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -8,6 +8,7 @@
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*/
+#include <linux/clk.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -24,6 +25,7 @@
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/reset.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -266,6 +268,12 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
return 0;
}
+static const struct clk_bulk_data dwc3_core_clks[] = {
+ { .id = "ref" },
+ { .id = "bus_early" },
+ { .id = "suspend" },
+};
+
/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
* @dwc3: Pointer to our controller context structure
@@ -667,6 +675,9 @@ static void dwc3_core_exit(struct dwc3 *dwc)
usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
+ clk_bulk_disable(dwc->num_clks, dwc->clks);
+ clk_bulk_unprepare(dwc->num_clks, dwc->clks);
+ reset_control_assert(dwc->reset);
}
static bool dwc3_core_is_valid(struct dwc3 *dwc)
@@ -1256,6 +1267,12 @@ static int dwc3_probe(struct platform_device *pdev)
if (!dwc)
return -ENOMEM;
+ dwc->clks = devm_kmemdup(dev, dwc3_core_clks, sizeof(dwc3_core_clks),
+ GFP_KERNEL);
+ if (!dwc->clks)
+ return -ENOMEM;
+
+ dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
dwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1286,6 +1303,32 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_properties(dwc);
+ dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(dwc->reset))
+ return PTR_ERR(dwc->reset);
+
+ ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ /*
+ * Clocks are optional, but new DT platforms should support all clocks
+ * as required by the DT-binding.
+ */
+ if (ret)
+ dwc->num_clks = 0;
+
+ ret = reset_control_deassert(dwc->reset);
+ if (ret)
+ goto put_clks;
+
+ ret = clk_bulk_prepare(dwc->num_clks, dwc->clks);
+ if (ret)
+ goto assert_reset;
+
+ ret = clk_bulk_enable(dwc->num_clks, dwc->clks);
+ if (ret)
+ goto unprepare_clks;
+
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
@@ -1349,6 +1392,14 @@ static int dwc3_probe(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ clk_bulk_disable(dwc->num_clks, dwc->clks);
+unprepare_clks:
+ clk_bulk_unprepare(dwc->num_clks, dwc->clks);
+assert_reset:
+ reset_control_assert(dwc->reset);
+put_clks:
+ clk_bulk_put(dwc->num_clks, dwc->clks);
+
return ret;
}
@@ -1370,11 +1421,44 @@ static int dwc3_remove(struct platform_device *pdev)
dwc3_free_event_buffers(dwc);
dwc3_free_scratch_buffers(dwc);
+ clk_bulk_put(dwc->num_clks, dwc->clks);
return 0;
}
#ifdef CONFIG_PM
+static int dwc3_core_init_for_resume(struct dwc3 *dwc)
+{
+ int ret;
+
+ ret = reset_control_deassert(dwc->reset);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare(dwc->num_clks, dwc->clks);
+ if (ret)
+ goto assert_reset;
+
+ ret = clk_bulk_enable(dwc->num_clks, dwc->clks);
+ if (ret)
+ goto unprepare_clks;
+
+ ret = dwc3_core_init(dwc);
+ if (ret)
+ goto disable_clks;
+
+ return 0;
+
+disable_clks:
+ clk_bulk_disable(dwc->num_clks, dwc->clks);
+unprepare_clks:
+ clk_bulk_unprepare(dwc->num_clks, dwc->clks);
+assert_reset:
+ reset_control_assert(dwc->reset);
+
+ return ret;
+}
+
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
{
unsigned long flags;
@@ -1420,7 +1504,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
- ret = dwc3_core_init(dwc);
+ ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;
@@ -1432,7 +1516,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
case DWC3_GCTL_PRTCAP_HOST:
/* nothing to do on host runtime_resume */
if (!PMSG_IS_AUTO(msg)) {
- ret = dwc3_core_init(dwc);
+ ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4f3b438..1765e01 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -891,6 +891,9 @@ struct dwc3_scratchpad_array {
* @eps: endpoint array
* @gadget: device side representation of the peripheral controller
* @gadget_driver: pointer to the gadget driver
+ * @clks: array of clocks
+ * @num_clks: number of clocks
+ * @reset: reset control
* @regs: base address for our registers
* @regs_size: address space size
* @fladj: frame length adjustment
@@ -1013,6 +1016,11 @@ struct dwc3 {
struct usb_gadget gadget;
struct usb_gadget_driver *gadget_driver;
+ struct clk_bulk_data *clks;
+ int num_clks;
+
+ struct reset_control *reset;
+
struct usb_phy *usb2_phy;
struct usb_phy *usb3_phy;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 0/3] irqchip: meson-gpio: add support for Meson-AXG SoCs
From: Yixun Lan @ 2018-05-16 2:50 UTC (permalink / raw)
To: Marc Zyngier, Jason Cooper, Thomas Gleixner, Kevin Hilman
Cc: yixun.lan, Carlo Caione, Jerome Brunet, Heiner Kallweit,
Rob Herring, Xingyu Chen, linux-amlogic, linux-arm-kernel,
linux-kernel, devicetree
In-Reply-To: <20180408145700.23520-1-yixun.lan@amlogic.com>
Hi Marc (or anyone else)
On 04/08/18 22:56, Yixun Lan wrote:
> This series try to add GPIO interrupt controller support for Meson-AXG SoCs.
> The first patch is a trivial typo fix, I can fold the first two patches
> together if necessary.
>
> Yixun Lan (3):
> dt-bindings: interrupt-controller: fix the double quotes
> dt-bindings: interrupt-controller: New binding for Meson-AXG SoC
> irqchip/meson-gpio: add support for Meson-AXG SoCs
>
> .../bindings/interrupt-controller/amlogic,meson-gpio-intc.txt | 11 ++++++-----
> drivers/irqchip/irq-meson-gpio.c | 5 +++++
> 2 files changed, 11 insertions(+), 5 deletions(-)
>
please consider this merely a ping..
will you take this series, or is there anything holding this?
thanks
Yixun
^ permalink raw reply
* Re: [PATCH v7 12/14] cpufreq: Add Kryo CPU scaling driver
From: kbuild test robot @ 2018-05-16 4:13 UTC (permalink / raw)
Cc: kbuild-all, mturquette, sboyd, robh, mark.rutland, viresh.kumar,
nm, lgirdwood, broonie, andy.gross, david.brown, catalin.marinas,
will.deacon, rjw, linux-clk, devicetree, linux-kernel, linux-pm,
linux-arm-msm, linux-soc, linux-arm-kernel, rnayak, ilialin,
amit.kucheria, nicolas.dechesne, celster, tfinkel
In-Reply-To: <1526375616-16904-13-git-send-email-ilialin@codeaurora.org>
[-- Attachment #1: Type: text/plain, Size: 1659 bytes --]
Hi Ilia,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.17-rc5]
[cannot apply to clk/clk-next next-20180515]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ilia-Lin/CPU-scaling-support-for-msm8996/20180516-064721
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
All errors (new ones prefixed by >>):
aarch64-linux-gnu-ld: arch/arm64/kernel/head.o: relocation R_AARCH64_ABS32 against `_kernel_offset_le_lo32' can not be used when making a shared object
arch/arm64/kernel/head.o: In function `kimage_vaddr':
(.idmap.text+0x0): dangerous relocation: unsupported relocation
arch/arm64/kernel/head.o: In function `__primary_switch':
(.idmap.text+0x350): dangerous relocation: unsupported relocation
(.idmap.text+0x358): dangerous relocation: unsupported relocation
drivers/cpufreq/qcom-cpufreq-kryo.o: In function `qcom_cpufreq_kryo_driver_init':
>> qcom-cpufreq-kryo.c:(.init.text+0xd8): undefined reference to `qcom_smem_get'
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 59061 bytes --]
^ permalink raw reply
* Re: [RFC PATCH V2] scsi: ufs: Add specific callback for setting DMA mask
From: Alim Akhtar @ 2018-05-16 4:31 UTC (permalink / raw)
To: Alim Akhtar
Cc: linux-scsi, linux-kernel, jejb, martin.petersen,
vinayak holikatti, subhashj, devicetree, Shaik Ameer Basha
In-Reply-To: <1520507013-2410-1-git-send-email-alim.akhtar@samsung.com>
Ping !!!
On Thu, Mar 8, 2018 at 4:33 PM, Alim Akhtar <alim.akhtar@samsung.com> wrote:
> Currently DMA mask for UFS HCI is set by reading CAP register's
> [64AS] bit. Some HCI controller like Exynos support 36-bit bus address.
> This works perfectly fine with DMA mask set as 64 in case there is no
> IOMMU attached to HCI.
> In case if HCI is behind an IOMMU, setting DMA mask as 64 bit won't
> work as HCI has only 36bit addressing and SMMU has created mapping of
> 64 bit and as the device truncates the address, its mapping will not
> be found by iommu.
> To resolve such issues, let the variant driver sets its own DMA mask.
>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> drivers/scsi/ufs/ufshcd.c | 3 +++
> drivers/scsi/ufs/ufshcd.h | 2 ++
> 2 files changed, 5 insertions(+)
>
> I am not sure if there are other ways available to handle such cases.
> The IOMMU I am talking about is arm-smmu and it DT binding does not
> give much idea about handling such cases.
> Have tested this patch with HCI controller with IOMMU attached.
>
> Changes Since V1:
> - Fixed build issue as reported by Kbuild test robot.
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index a355d98..9a1374e 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -7781,6 +7781,9 @@ EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
> */
> static int ufshcd_set_dma_mask(struct ufs_hba *hba)
> {
> + if (hba->vops && hba->vops->set_dma_mask)
> + return hba->vops->set_dma_mask(hba);
> +
> if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT) {
> if (!dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(64)))
> return 0;
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 1332e54..89c6dae 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -297,6 +297,7 @@ struct ufs_pwr_mode_info {
> * @resume: called during host controller PM callback
> * @dbg_register_dump: used to dump controller debug information
> * @phy_initialization: used to initialize phys
> + * @set_dma_mask: used to set variant specific DMA mask
> */
> struct ufs_hba_variant_ops {
> const char *name;
> @@ -325,6 +326,7 @@ struct ufs_hba_variant_ops {
> int (*resume)(struct ufs_hba *, enum ufs_pm_op);
> void (*dbg_register_dump)(struct ufs_hba *hba);
> int (*phy_initialization)(struct ufs_hba *);
> + int (*set_dma_mask)(struct ufs_hba *hba);
> };
>
> /* clock gating state */
> --
> 2.7.4
>
--
Regards,
Alim
^ permalink raw reply
* [PATCH] ARM: dts: imx7d: use operating-points-v2 for cpu
From: Anson Huang @ 2018-05-16 4:48 UTC (permalink / raw)
To: shawnguo, kernel, fabio.estevam, robh+dt, mark.rutland
Cc: Linux-imx, linux-arm-kernel, devicetree, linux-kernel
This patch uses "operating-points-v2" instead of
"operating-points" to be more fit with cpufreq-dt
driver.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
arch/arm/boot/dts/imx7d.dtsi | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index 4c9877e..28980c8 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -9,12 +9,8 @@
/ {
cpus {
cpu0: cpu@0 {
- operating-points = <
- /* KHz uV */
- 996000 1075000
- 792000 975000
- >;
clock-frequency = <996000000>;
+ operating-points-v2 = <&cpu0_opp_table>;
};
cpu1: cpu@1 {
@@ -22,6 +18,24 @@
device_type = "cpu";
reg = <1>;
clock-frequency = <996000000>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+
+ cpu0_opp_table: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp-792000000 {
+ opp-hz = /bits/ 64 <792000000>;
+ opp-microvolt = <975000>;
+ clock-latency-ns = <150000>;
+ };
+ opp-996000000 {
+ opp-hz = /bits/ 64 <996000000>;
+ opp-microvolt = <1075000>;
+ clock-latency-ns = <150000>;
+ opp-suspend;
};
};
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v6 04/17] media: rkisp1: add Rockchip MIPI Synopsys DPHY driver
From: Laurent Pinchart @ 2018-05-16 5:20 UTC (permalink / raw)
To: Jacob Chen
Cc: linux-rockchip, linux-kernel, linux-arm-kernel, mchehab,
linux-media, sakari.ailus, hans.verkuil, tfiga, zhengsq, zyc,
eddie.cai.linux, jeffy.chen, devicetree, heiko, Jacob Chen
In-Reply-To: <20180308094807.9443-5-jacob-chen@iotwrt.com>
Hi Jacob,
Thank you for the patch.
On Thursday, 8 March 2018 11:47:54 EEST Jacob Chen wrote:
> From: Jacob Chen <jacob2.chen@rock-chips.com>
>
> This commit adds a subdev driver for Rockchip MIPI Synopsys DPHY driver
Should this really be a subdev driver ? After a quick look at the code, the
only parameters you need to configure the PHY is the number of lanes and the
data rate. Implementing the whole subdev API seems overcomplicated to me,
especially given that the D-PHY doesn't deal with video streams as such, but
operates one level down. Shouldn't we model the D-PHY using the Linux PHY
framework ? I believe all the features you need are there except for a D-PHY-
specific configuration function that should be very easy to add.
> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
> Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> ---
> .../media/platform/rockchip/isp1/mipi_dphy_sy.c | 868 ++++++++++++++++++
> .../media/platform/rockchip/isp1/mipi_dphy_sy.h | 15 +
> 2 files changed, 883 insertions(+)
> create mode 100644 drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
> create mode 100644 drivers/media/platform/rockchip/isp1/mipi_dphy_sy.h
>
> diff --git a/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
> b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c new file mode 100644
> index 000000000000..32140960557a
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
> @@ -0,0 +1,868 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Rockchip MIPI Synopsys DPHY driver
> + *
> + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <media/media-entity.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
> +
> +#define RK3288_GRF_SOC_CON6 0x025c
> +#define RK3288_GRF_SOC_CON8 0x0264
> +#define RK3288_GRF_SOC_CON9 0x0268
> +#define RK3288_GRF_SOC_CON10 0x026c
> +#define RK3288_GRF_SOC_CON14 0x027c
> +#define RK3288_GRF_SOC_STATUS21 0x02d4
> +#define RK3288_GRF_IO_VSEL 0x0380
> +#define RK3288_GRF_SOC_CON15 0x03a4
> +
> +#define RK3399_GRF_SOC_CON9 0x6224
> +#define RK3399_GRF_SOC_CON21 0x6254
> +#define RK3399_GRF_SOC_CON22 0x6258
> +#define RK3399_GRF_SOC_CON23 0x625c
> +#define RK3399_GRF_SOC_CON24 0x6260
> +#define RK3399_GRF_SOC_CON25 0x6264
> +#define RK3399_GRF_SOC_STATUS1 0xe2a4
> +
> +#define CLOCK_LANE_HS_RX_CONTROL 0x34
> +#define LANE0_HS_RX_CONTROL 0x44
> +#define LANE1_HS_RX_CONTROL 0x54
> +#define LANE2_HS_RX_CONTROL 0x84
> +#define LANE3_HS_RX_CONTROL 0x94
> +#define HS_RX_DATA_LANES_THS_SETTLE_CONTROL 0x75
> +
> +/*
> + * CSI HOST
> + */
> +#define CSIHOST_PHY_TEST_CTRL0 0x30
> +#define CSIHOST_PHY_TEST_CTRL1 0x34
> +#define CSIHOST_PHY_SHUTDOWNZ 0x08
> +#define CSIHOST_DPHY_RSTZ 0x0c
> +
> +#define PHY_TESTEN_ADDR (0x1 << 16)
> +#define PHY_TESTEN_DATA (0x0 << 16)
> +#define PHY_TESTCLK (0x1 << 1)
> +#define PHY_TESTCLR (0x1 << 0)
> +#define THS_SETTLE_COUNTER_THRESHOLD 0x04
> +
> +#define HIWORD_UPDATE(val, mask, shift) \
> + ((val) << (shift) | (mask) << ((shift) + 16))
> +
> +enum mipi_dphy_sy_pads {
> + MIPI_DPHY_SY_PAD_SINK = 0,
> + MIPI_DPHY_SY_PAD_SOURCE,
> + MIPI_DPHY_SY_PADS_NUM,
> +};
> +
> +enum dphy_reg_id {
> + GRF_DPHY_RX0_TURNDISABLE = 0,
> + GRF_DPHY_RX0_FORCERXMODE,
> + GRF_DPHY_RX0_FORCETXSTOPMODE,
> + GRF_DPHY_RX0_ENABLE,
> + GRF_DPHY_RX0_TESTCLR,
> + GRF_DPHY_RX0_TESTCLK,
> + GRF_DPHY_RX0_TESTEN,
> + GRF_DPHY_RX0_TESTDIN,
> + GRF_DPHY_RX0_TURNREQUEST,
> + GRF_DPHY_RX0_TESTDOUT,
> + GRF_DPHY_TX0_TURNDISABLE,
> + GRF_DPHY_TX0_FORCERXMODE,
> + GRF_DPHY_TX0_FORCETXSTOPMODE,
> + GRF_DPHY_TX0_TURNREQUEST,
> + GRF_DPHY_TX1RX1_TURNDISABLE,
> + GRF_DPHY_TX1RX1_FORCERXMODE,
> + GRF_DPHY_TX1RX1_FORCETXSTOPMODE,
> + GRF_DPHY_TX1RX1_ENABLE,
> + GRF_DPHY_TX1RX1_MASTERSLAVEZ,
> + GRF_DPHY_TX1RX1_BASEDIR,
> + GRF_DPHY_TX1RX1_ENABLECLK,
> + GRF_DPHY_TX1RX1_TURNREQUEST,
> + GRF_DPHY_RX1_SRC_SEL,
> + /* rk3288 only */
> + GRF_CON_DISABLE_ISP,
> + GRF_CON_ISP_DPHY_SEL,
> + GRF_DSI_CSI_TESTBUS_SEL,
> + GRF_DVP_V18SEL,
> + /* below is for rk3399 only */
> + GRF_DPHY_RX0_CLK_INV_SEL,
> + GRF_DPHY_RX1_CLK_INV_SEL,
> +};
> +
> +struct dphy_reg {
> + u32 offset;
> + u32 mask;
> + u32 shift;
> +};
> +
> +#define PHY_REG(_offset, _width, _shift) \
> + { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
> +
> +static const struct dphy_reg rk3399_grf_dphy_regs[] = {
> + [GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON9, 4, 0),
> + [GRF_DPHY_RX0_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 10),
> + [GRF_DPHY_RX1_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 11),
> + [GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 0),
> + [GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 4),
> + [GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 8),
> + [GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 12),
> + [GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 0),
> + [GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 4),
> + [GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 8),
> + [GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 12),
> + [GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 0),
> + [GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 4),
> + [GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 8),
> + [GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 12),
> + [GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON24, 4, 0),
> + [GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 4),
> + [GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 5),
> + [GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 6),
> + [GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 7),
> + [GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3399_GRF_SOC_CON25, 8, 0),
> + [GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 8),
> + [GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 9),
> + [GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 10),
> + [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3399_GRF_SOC_STATUS1, 8, 0),
> +};
> +
> +static const struct dphy_reg rk3288_grf_dphy_regs[] = {
> + [GRF_CON_DISABLE_ISP] = PHY_REG(RK3288_GRF_SOC_CON6, 1, 0),
> + [GRF_CON_ISP_DPHY_SEL] = PHY_REG(RK3288_GRF_SOC_CON6, 1, 1),
> + [GRF_DSI_CSI_TESTBUS_SEL] = PHY_REG(RK3288_GRF_SOC_CON6, 1, 14),
> + [GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3288_GRF_SOC_CON8, 4, 0),
> + [GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3288_GRF_SOC_CON8, 4, 4),
> + [GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3288_GRF_SOC_CON8, 4, 8),
> + [GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3288_GRF_SOC_CON9, 4, 0),
> + [GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3288_GRF_SOC_CON9, 4, 4),
> + [GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3288_GRF_SOC_CON9, 4, 8),
> + [GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3288_GRF_SOC_CON9, 4, 12),
> + [GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3288_GRF_SOC_CON10, 4, 0),
> + [GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3288_GRF_SOC_CON10, 4, 4),
> + [GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3288_GRF_SOC_CON10, 4, 8),
> + [GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3288_GRF_SOC_CON10, 4, 12),
> + [GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 0),
> + [GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 1),
> + [GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 2),
> + [GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3288_GRF_SOC_CON14, 8, 3),
> + [GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 12),
> + [GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 13),
> + [GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 14),
> + [GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3288_GRF_SOC_CON14, 1, 15),
> + [GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3288_GRF_SOC_CON15, 4, 0),
> + [GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3288_GRF_SOC_CON15, 4, 4),
> + [GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3288_GRF_SOC_CON15, 3, 8),
> + [GRF_DVP_V18SEL] = PHY_REG(RK3288_GRF_IO_VSEL, 1, 1),
> + [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3288_GRF_SOC_STATUS21, 8, 0),
> +};
> +
> +struct hsfreq_range {
> + u32 range_h;
> + u8 cfg_bit;
> +};
> +
> +struct mipidphy_priv;
> +
> +struct dphy_drv_data {
> + const char * const *clks;
> + int num_clks;
> + const struct hsfreq_range *hsfreq_ranges;
> + int num_hsfreq_ranges;
> + const struct dphy_reg *regs;
> +};
> +
> +struct sensor_async_subdev {
> + struct v4l2_async_subdev asd;
> + struct v4l2_mbus_config mbus;
> + int lanes;
> +};
> +
> +#define MAX_DPHY_CLK 8
> +#define MAX_DPHY_SENSORS 2
> +
> +struct mipidphy_sensor {
> + struct v4l2_subdev *sd;
> + struct v4l2_mbus_config mbus;
> + int lanes;
> +};
> +
> +struct mipidphy_priv {
> + struct device *dev;
> + struct regmap *regmap_grf;
> + const struct dphy_reg *grf_regs;
> + struct clk *clks[MAX_DPHY_CLK];
> + const struct dphy_drv_data *drv_data;
> + u64 data_rate_mbps;
> + struct v4l2_async_notifier notifier;
> + struct v4l2_subdev sd;
> + struct media_pad pads[MIPI_DPHY_SY_PADS_NUM];
> + struct mipidphy_sensor sensors[MAX_DPHY_SENSORS];
> + int num_sensors;
> + bool is_streaming;
> + void __iomem *txrx_base_addr;
> + int (*stream_on)(struct mipidphy_priv *priv, struct v4l2_subdev *sd);
> +};
> +
> +static inline struct mipidphy_priv *to_dphy_priv(struct v4l2_subdev
> *subdev) +{
> + return container_of(subdev, struct mipidphy_priv, sd);
> +}
> +
> +static inline void write_grf_reg(struct mipidphy_priv *priv,
> + int index, u8 value)
> +{
> + const struct dphy_reg *reg = &priv->grf_regs[index];
> + unsigned int val = HIWORD_UPDATE(value, reg->mask, reg->shift);
> +
> + WARN_ON(!reg->offset);
> + regmap_write(priv->regmap_grf, reg->offset, val);
> +}
> +
> +static void mipidphy0_wr_reg(struct mipidphy_priv *priv,
> + u8 test_code, u8 test_data)
> +{
> + /*
> + * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
> + * is latched internally as the current test code. Test data is
> + * programmed internally by rising edge on TESTCLK.
> + */
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTCLK, 1);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTDIN, test_code);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTEN, 1);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTCLK, 0);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTEN, 0);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTDIN, test_data);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTCLK, 1);
> +}
> +
> +static void mipidphy1_wr_reg(struct mipidphy_priv *priv, unsigned char
> addr, + unsigned char data)
> +{
> + /*
> + * TESTEN =1,TESTDIN=addr
> + * TESTCLK=0
> + * TESTEN =0,TESTDIN=data
> + * TESTCLK=1
> + */
> + writel((PHY_TESTEN_ADDR | addr),
> + priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL1);
> + writel(0x00, priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL0);
> + writel((PHY_TESTEN_DATA | data),
> + priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL1);
> + writel(PHY_TESTCLK, priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL0);
> +}
> +
> +static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd)
> +{
> + struct media_pad *local, *remote;
> + struct media_entity *sensor_me;
> +
> + local = &sd->entity.pads[MIPI_DPHY_SY_PAD_SINK];
> + remote = media_entity_remote_pad(local);
> + if (!remote) {
> + v4l2_warn(sd, "No link between dphy and sensor\n");
> + return NULL;
> + }
> +
> + sensor_me = media_entity_remote_pad(local)->entity;
> + return media_entity_to_v4l2_subdev(sensor_me);
> +}
> +
> +static struct mipidphy_sensor *sd_to_sensor(struct mipidphy_priv *priv,
> + struct v4l2_subdev *sd)
> +{
> + int i;
> +
> + for (i = 0; i < priv->num_sensors; ++i)
> + if (priv->sensors[i].sd == sd)
> + return &priv->sensors[i];
> +
> + return NULL;
> +}
> +
> +static int mipidphy_get_sensor_data_rate(struct v4l2_subdev *sd)
> +{
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
> + struct v4l2_ctrl *link_freq;
> + struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ, };
> + int ret;
> +
> + link_freq = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_LINK_FREQ);
> + if (!link_freq) {
> + v4l2_warn(sd, "No pixel rate control in subdev\n");
> + return -EPIPE;
> + }
> +
> + qm.index = v4l2_ctrl_g_ctrl(link_freq);
> + ret = v4l2_querymenu(sensor_sd->ctrl_handler, &qm);
> + if (ret < 0) {
> + v4l2_err(sd, "Failed to get menu item\n");
> + return ret;
> + }
> +
> + if (!qm.value) {
> + v4l2_err(sd, "Invalid link_freq\n");
> + return -EINVAL;
> + }
> + priv->data_rate_mbps = qm.value * 2;
> + do_div(priv->data_rate_mbps, 1000 * 1000);
> +
> + return 0;
> +}
> +
> +static int mipidphy_s_stream_start(struct v4l2_subdev *sd)
> +{
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> + int ret = 0;
> +
> + if (priv->is_streaming)
> + return 0;
> +
> + ret = mipidphy_get_sensor_data_rate(sd);
> + if (ret < 0)
> + return ret;
> +
> + priv->stream_on(priv, sd);
> +
> + priv->is_streaming = true;
> +
> + return 0;
> +}
> +
> +static int mipidphy_s_stream_stop(struct v4l2_subdev *sd)
> +{
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> +
> + priv->is_streaming = false;
> +
> + return 0;
> +}
> +
> +static int mipidphy_s_stream(struct v4l2_subdev *sd, int on)
> +{
> + if (on)
> + return mipidphy_s_stream_start(sd);
> + else
> + return mipidphy_s_stream_stop(sd);
> +}
> +
> +static int mipidphy_g_mbus_config(struct v4l2_subdev *sd,
> + struct v4l2_mbus_config *config)
> +{
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
> + struct mipidphy_sensor *sensor = sd_to_sensor(priv, sensor_sd);
> +
> + *config = sensor->mbus;
> +
> + return 0;
> +}
> +
> +static int mipidphy_s_power(struct v4l2_subdev *sd, int on)
> +{
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> +
> + if (on)
> + return pm_runtime_get_sync(priv->dev);
> + else
> + return pm_runtime_put(priv->dev);
> +}
> +
> +static int mipidphy_runtime_suspend(struct device *dev)
> +{
> + struct media_entity *me = dev_get_drvdata(dev);
> + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> + int i, num_clks;
> +
> + num_clks = priv->drv_data->num_clks;
> + for (i = num_clks - 1; i >= 0; i--)
> + clk_disable_unprepare(priv->clks[i]);
> +
> + return 0;
> +}
> +
> +static int mipidphy_runtime_resume(struct device *dev)
> +{
> + struct media_entity *me = dev_get_drvdata(dev);
> + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
> + struct mipidphy_priv *priv = to_dphy_priv(sd);
> + int i, num_clks, ret;
> +
> + num_clks = priv->drv_data->num_clks;
> + for (i = 0; i < num_clks; i++) {
> + ret = clk_prepare_enable(priv->clks[i]);
> + if (ret < 0)
> + goto err;
> + }
> +
> + return 0;
> +err:
> + while (--i >= 0)
> + clk_disable_unprepare(priv->clks[i]);
> + return ret;
> +}
> +
> +/* dphy accepts all fmt/size from sensor */
> +static int mipidphy_get_set_fmt(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *fmt)
> +{
> + struct v4l2_subdev *sensor = get_remote_sensor(sd);
> +
> + /*
> + * Do not allow format changes and just relay whatever
> + * set currently in the sensor.
> + */
> + return v4l2_subdev_call(sensor, pad, get_fmt, NULL, fmt);
> +}
> +
> +static const struct v4l2_subdev_pad_ops mipidphy_subdev_pad_ops = {
> + .set_fmt = mipidphy_get_set_fmt,
> + .get_fmt = mipidphy_get_set_fmt,
> +};
> +
> +static const struct v4l2_subdev_core_ops mipidphy_core_ops = {
> + .s_power = mipidphy_s_power,
> +};
> +
> +static const struct v4l2_subdev_video_ops mipidphy_video_ops = {
> + .g_mbus_config = mipidphy_g_mbus_config,
> + .s_stream = mipidphy_s_stream,
> +};
> +
> +static const struct v4l2_subdev_ops mipidphy_subdev_ops = {
> + .core = &mipidphy_core_ops,
> + .video = &mipidphy_video_ops,
> + .pad = &mipidphy_subdev_pad_ops,
> +};
> +
> +/* These tables must be sorted by .range_h ascending. */
> +static const struct hsfreq_range rk3288_mipidphy_hsfreq_ranges[] = {
> + { 89, 0x00}, { 99, 0x10}, { 109, 0x20}, { 129, 0x01},
> + { 139, 0x11}, { 149, 0x21}, { 169, 0x02}, { 179, 0x12},
> + { 199, 0x22}, { 219, 0x03}, { 239, 0x13}, { 249, 0x23},
> + { 269, 0x04}, { 299, 0x14}, { 329, 0x05}, { 359, 0x15},
> + { 399, 0x25}, { 449, 0x06}, { 499, 0x16}, { 549, 0x07},
> + { 599, 0x17}, { 649, 0x08}, { 699, 0x18}, { 749, 0x09},
> + { 799, 0x19}, { 849, 0x29}, { 899, 0x39}, { 949, 0x0a},
> + { 999, 0x1a}
> +};
> +
> +static const struct hsfreq_range rk3399_mipidphy_hsfreq_ranges[] = {
> + { 89, 0x00}, { 99, 0x10}, { 109, 0x20}, { 129, 0x01},
> + { 139, 0x11}, { 149, 0x21}, { 169, 0x02}, { 179, 0x12},
> + { 199, 0x22}, { 219, 0x03}, { 239, 0x13}, { 249, 0x23},
> + { 269, 0x04}, { 299, 0x14}, { 329, 0x05}, { 359, 0x15},
> + { 399, 0x25}, { 449, 0x06}, { 499, 0x16}, { 549, 0x07},
> + { 599, 0x17}, { 649, 0x08}, { 699, 0x18}, { 749, 0x09},
> + { 799, 0x19}, { 849, 0x29}, { 899, 0x39}, { 949, 0x0a},
> + { 999, 0x1a}, {1049, 0x2a}, {1099, 0x3a}, {1149, 0x0b},
> + {1199, 0x1b}, {1249, 0x2b}, {1299, 0x3b}, {1349, 0x0c},
> + {1399, 0x1c}, {1449, 0x2c}, {1500, 0x3c}
> +};
> +
> +static const char * const rk3399_mipidphy_clks[] = {
> + "dphy-ref",
> + "dphy-cfg",
> + "grf",
> +};
> +
> +static const char * const rk3288_mipidphy_clks[] = {
> + "dphy-ref",
> + "pclk",
> +};
> +
> +static int mipidphy_rx_stream_on(struct mipidphy_priv *priv,
> + struct v4l2_subdev *sd)
> +{
> + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
> + struct mipidphy_sensor *sensor = sd_to_sensor(priv, sensor_sd);
> + const struct dphy_drv_data *drv_data = priv->drv_data;
> + const struct hsfreq_range *hsfreq_ranges = drv_data->hsfreq_ranges;
> + int num_hsfreq_ranges = drv_data->num_hsfreq_ranges;
> + int i, hsfreq = 0;
> +
> + for (i = 0; i < num_hsfreq_ranges; i++) {
> + if (hsfreq_ranges[i].range_h >= priv->data_rate_mbps) {
> + hsfreq = hsfreq_ranges[i].cfg_bit;
> + break;
> + }
> + }
> + write_grf_reg(priv, GRF_CON_ISP_DPHY_SEL, 0);
> + write_grf_reg(priv, GRF_DPHY_RX0_FORCERXMODE, 0);
> + write_grf_reg(priv, GRF_DPHY_RX0_FORCETXSTOPMODE, 0);
> + /* Disable lan turn around, which is ignored in receive mode */
> + write_grf_reg(priv, GRF_DPHY_RX0_TURNREQUEST, 0);
> + write_grf_reg(priv, GRF_DPHY_RX0_TURNDISABLE, 0xf);
> +
> + write_grf_reg(priv, GRF_DPHY_RX0_ENABLE, GENMASK(sensor->lanes - 1, 0));
> +
> + /* dphy start */
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTCLK, 1);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTCLR, 1);
> + usleep_range(100, 150);
> + write_grf_reg(priv, GRF_DPHY_RX0_TESTCLR, 0);
> + usleep_range(100, 150);
> +
> + /* set clock lane */
> + /* HS hsfreq_range & lane 0 settle bypass */
> + mipidphy0_wr_reg(priv, CLOCK_LANE_HS_RX_CONTROL, 0);
> + /* HS RX Control of lane0 */
> + mipidphy0_wr_reg(priv, LANE0_HS_RX_CONTROL, hsfreq << 1);
> + /* HS RX Control of lane1 */
> + mipidphy0_wr_reg(priv, LANE1_HS_RX_CONTROL, 0);
> + /* HS RX Control of lane2 */
> + mipidphy0_wr_reg(priv, LANE2_HS_RX_CONTROL, 0);
> + /* HS RX Control of lane3 */
> + mipidphy0_wr_reg(priv, LANE3_HS_RX_CONTROL, 0);
> + /* HS RX Data Lanes Settle State Time Control */
> + mipidphy0_wr_reg(priv, HS_RX_DATA_LANES_THS_SETTLE_CONTROL,
> + THS_SETTLE_COUNTER_THRESHOLD);
> +
> + /* Normal operation */
> + mipidphy0_wr_reg(priv, 0x0, 0);
> +
> + return 0;
> +}
> +
> +static int mipidphy_txrx_stream_on(struct mipidphy_priv *priv,
> + struct v4l2_subdev *sd)
> +{
> + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
> + struct mipidphy_sensor *sensor = sd_to_sensor(priv, sensor_sd);
> + const struct dphy_drv_data *drv_data = priv->drv_data;
> + const struct hsfreq_range *hsfreq_ranges = drv_data->hsfreq_ranges;
> + int num_hsfreq_ranges = drv_data->num_hsfreq_ranges;
> + int i, hsfreq = 0;
> +
> + for (i = 0; i < num_hsfreq_ranges; i++) {
> + if (hsfreq_ranges[i].range_h >= priv->data_rate_mbps) {
> + hsfreq = hsfreq_ranges[i].cfg_bit;
> + break;
> + }
> + }
> + write_grf_reg(priv, GRF_CON_ISP_DPHY_SEL, 1);
> + write_grf_reg(priv, GRF_DSI_CSI_TESTBUS_SEL, 1);
> + write_grf_reg(priv, GRF_DPHY_RX1_SRC_SEL, 1);
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_MASTERSLAVEZ, 0);
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_BASEDIR, 1);
> + /* Disable lan turn around, which is ignored in receive mode */
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_FORCERXMODE, 0);
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_FORCETXSTOPMODE, 0);
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_TURNREQUEST, 0);
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_TURNDISABLE, 0xf);
> + write_grf_reg(priv, GRF_DPHY_TX1RX1_ENABLE,
> + GENMASK(sensor->lanes - 1, 0));
> + /* dphy start */
> + writel(0, priv->txrx_base_addr + CSIHOST_PHY_SHUTDOWNZ);
> + writel(0, priv->txrx_base_addr + CSIHOST_DPHY_RSTZ);
> + writel(PHY_TESTCLK, priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL0);
> + writel(PHY_TESTCLR, priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL0);
> + usleep_range(100, 150);
> + writel(PHY_TESTCLK, priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL0);
> + usleep_range(100, 150);
> +
> + /* set clock lane */
> + mipidphy1_wr_reg(priv, CLOCK_LANE_HS_RX_CONTROL, 0);
> + mipidphy1_wr_reg(priv, LANE0_HS_RX_CONTROL, hsfreq << 1);
> + mipidphy1_wr_reg(priv, LANE1_HS_RX_CONTROL, 0);
> + mipidphy1_wr_reg(priv, LANE2_HS_RX_CONTROL, 0);
> + mipidphy1_wr_reg(priv, LANE3_HS_RX_CONTROL, 0);
> + /* HS RX Data Lanes Settle State Time Control */
> + mipidphy1_wr_reg(priv, HS_RX_DATA_LANES_THS_SETTLE_CONTROL,
> + THS_SETTLE_COUNTER_THRESHOLD);
> +
> + /* Normal operation */
> + mipidphy1_wr_reg(priv, 0x0, 0);
> +
> + return 0;
> +}
> +
> +static const struct dphy_drv_data rk3288_mipidphy_drv_data = {
> + .clks = rk3288_mipidphy_clks,
> + .num_clks = ARRAY_SIZE(rk3288_mipidphy_clks),
> + .hsfreq_ranges = rk3288_mipidphy_hsfreq_ranges,
> + .num_hsfreq_ranges = ARRAY_SIZE(rk3288_mipidphy_hsfreq_ranges),
> + .regs = rk3288_grf_dphy_regs,
> +};
> +
> +static const struct dphy_drv_data rk3399_mipidphy_drv_data = {
> + .clks = rk3399_mipidphy_clks,
> + .num_clks = ARRAY_SIZE(rk3399_mipidphy_clks),
> + .hsfreq_ranges = rk3399_mipidphy_hsfreq_ranges,
> + .num_hsfreq_ranges = ARRAY_SIZE(rk3399_mipidphy_hsfreq_ranges),
> + .regs = rk3399_grf_dphy_regs,
> +};
> +
> +static const struct of_device_id rockchip_mipidphy_match_id[] = {
> + {
> + .compatible = "rockchip,rk3399-mipi-dphy",
> + .data = &rk3399_mipidphy_drv_data,
> + },
> + {
> + .compatible = "rockchip,rk3288-mipi-dphy",
> + .data = &rk3288_mipidphy_drv_data,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, rockchip_mipidphy_match_id);
> +
> +/* The .bound() notifier callback when a match is found */
> +static int
> +rockchip_mipidphy_notifier_bound(struct v4l2_async_notifier *notifier,
> + struct v4l2_subdev *sd,
> + struct v4l2_async_subdev *asd)
> +{
> + struct mipidphy_priv *priv = container_of(notifier,
> + struct mipidphy_priv,
> + notifier);
> + struct sensor_async_subdev *s_asd = container_of(asd,
> + struct sensor_async_subdev, asd);
> + struct mipidphy_sensor *sensor;
> + unsigned int pad, ret;
> +
> + if (priv->num_sensors == ARRAY_SIZE(priv->sensors))
> + return -EBUSY;
> +
> + sensor = &priv->sensors[priv->num_sensors++];
> + sensor->lanes = s_asd->lanes;
> + sensor->mbus = s_asd->mbus;
> + sensor->sd = sd;
> +
> + for (pad = 0; pad < sensor->sd->entity.num_pads; pad++)
> + if (sensor->sd->entity.pads[pad].flags
> + & MEDIA_PAD_FL_SOURCE)
> + break;
> +
> + if (pad == sensor->sd->entity.num_pads) {
> + dev_err(priv->dev,
> + "failed to find src pad for %s\n",
> + sensor->sd->name);
> +
> + return -ENXIO;
> + }
> +
> + ret = media_create_pad_link(
> + &sensor->sd->entity, pad,
> + &priv->sd.entity, MIPI_DPHY_SY_PAD_SINK,
> + priv->num_sensors != 1 ? 0 : MEDIA_LNK_FL_ENABLED);
> + if (ret) {
> + dev_err(priv->dev,
> + "failed to create link for %s\n",
> + sensor->sd->name);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/* The .unbind callback */
> +static void
> +rockchip_mipidphy_notifier_unbind(struct v4l2_async_notifier *notifier,
> + struct v4l2_subdev *sd,
> + struct v4l2_async_subdev *asd)
> +{
> + struct mipidphy_priv *priv = container_of(notifier,
> + struct mipidphy_priv,
> + notifier);
> + struct mipidphy_sensor *sensor = sd_to_sensor(priv, sd);
> +
> + sensor->sd = NULL;
> +}
> +
> +static const struct
> +v4l2_async_notifier_operations rockchip_mipidphy_async_ops = {
> + .bound = rockchip_mipidphy_notifier_bound,
> + .unbind = rockchip_mipidphy_notifier_unbind,
> +};
> +
> +static int rockchip_mipidphy_fwnode_parse(struct device *dev,
> + struct v4l2_fwnode_endpoint *vep,
> + struct v4l2_async_subdev *asd)
> +{
> + struct sensor_async_subdev *s_asd =
> + container_of(asd, struct sensor_async_subdev, asd);
> + struct v4l2_mbus_config *config = &s_asd->mbus;
> +
> + if (vep->bus_type != V4L2_MBUS_CSI2) {
> + dev_err(dev, "Only CSI2 bus type is currently supported\n");
> + return -EINVAL;
> + }
> +
> + if (vep->base.port != 0) {
> + dev_err(dev, "The PHY has only port 0\n");
> + return -EINVAL;
> + }
> +
> + config->type = V4L2_MBUS_CSI2;
> + config->flags = vep->bus.mipi_csi2.flags;
> + s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
> +
> + switch (vep->bus.mipi_csi2.num_data_lanes) {
> + case 1:
> + config->flags |= V4L2_MBUS_CSI2_1_LANE;
> + break;
> + case 2:
> + config->flags |= V4L2_MBUS_CSI2_2_LANE;
> + break;
> + case 3:
> + config->flags |= V4L2_MBUS_CSI2_3_LANE;
> + break;
> + case 4:
> + config->flags |= V4L2_MBUS_CSI2_4_LANE;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int rockchip_mipidphy_media_init(struct mipidphy_priv *priv)
> +{
> + int ret;
> +
> + priv->pads[MIPI_DPHY_SY_PAD_SOURCE].flags =
> + MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
> + priv->pads[MIPI_DPHY_SY_PAD_SINK].flags =
> + MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
> +
> + ret = media_entity_pads_init(&priv->sd.entity,
> + MIPI_DPHY_SY_PADS_NUM, priv->pads);
> + if (ret < 0)
> + return ret;
> +
> + ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> + priv->dev, &priv->notifier,
> + sizeof(struct sensor_async_subdev), 0,
> + rockchip_mipidphy_fwnode_parse);
> + if (ret < 0)
> + return ret;
> +
> + if (!priv->notifier.num_subdevs)
> + return -ENODEV; /* no endpoint */
> +
> + priv->sd.subdev_notifier = &priv->notifier;
> + priv->notifier.ops = &rockchip_mipidphy_async_ops;
> + ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier);
> + if (ret) {
> + dev_err(priv->dev,
> + "failed to register async notifier : %d\n", ret);
> + v4l2_async_notifier_cleanup(&priv->notifier);
> + return ret;
> + }
> +
> + return v4l2_async_register_subdev(&priv->sd);
> +}
> +
> +static int rockchip_mipidphy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct v4l2_subdev *sd;
> + struct mipidphy_priv *priv;
> + struct regmap *grf;
> + struct resource *res;
> + const struct of_device_id *of_id;
> + const struct dphy_drv_data *drv_data;
> + int i, ret;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> + priv->dev = dev;
> +
> + of_id = of_match_device(rockchip_mipidphy_match_id, dev);
> + if (!of_id)
> + return -EINVAL;
> +
> + grf = syscon_node_to_regmap(dev->parent->of_node);
> + if (IS_ERR(grf)) {
> + grf = syscon_regmap_lookup_by_phandle(dev->of_node,
> + "rockchip,grf");
> + if (IS_ERR(grf)) {
> + dev_err(dev, "Can't find GRF syscon\n");
> + return -ENODEV;
> + }
> + }
> + priv->regmap_grf = grf;
> +
> + drv_data = of_id->data;
> + for (i = 0; i < drv_data->num_clks; i++) {
> + priv->clks[i] = devm_clk_get(dev, drv_data->clks[i]);
> +
> + if (IS_ERR(priv->clks[i])) {
> + dev_err(dev, "Failed to get %s\n", drv_data->clks[i]);
> + return PTR_ERR(priv->clks[i]);
> + }
> + }
> +
> + priv->grf_regs = drv_data->regs;
> + priv->drv_data = drv_data;
> + priv->stream_on = mipidphy_txrx_stream_on;
> + priv->txrx_base_addr = NULL;
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->txrx_base_addr = devm_ioremap_resource(dev, res);
> + if (IS_ERR(priv->txrx_base_addr))
> + priv->stream_on = mipidphy_rx_stream_on;
> +
> + sd = &priv->sd;
> + v4l2_subdev_init(sd, &mipidphy_subdev_ops);
> + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> + snprintf(sd->name, sizeof(sd->name), "rockchip-sy-mipi-dphy");
> + sd->dev = dev;
> +
> + platform_set_drvdata(pdev, &sd->entity);
> +
> + ret = rockchip_mipidphy_media_init(priv);
> + if (ret < 0)
> + return ret;
> +
> + pm_runtime_enable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static int rockchip_mipidphy_remove(struct platform_device *pdev)
> +{
> + struct media_entity *me = platform_get_drvdata(pdev);
> + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
> +
> + media_entity_cleanup(&sd->entity);
> +
> + pm_runtime_disable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops rockchip_mipidphy_pm_ops = {
> + SET_RUNTIME_PM_OPS(mipidphy_runtime_suspend,
> + mipidphy_runtime_resume, NULL)
> +};
> +
> +static struct platform_driver rockchip_isp_mipidphy_driver = {
> + .probe = rockchip_mipidphy_probe,
> + .remove = rockchip_mipidphy_remove,
> + .driver = {
> + .name = "rockchip-sy-mipi-dphy",
> + .pm = &rockchip_mipidphy_pm_ops,
> + .of_match_table = rockchip_mipidphy_match_id,
> + },
> +};
> +
> +module_platform_driver(rockchip_isp_mipidphy_driver);
> +MODULE_AUTHOR("Rockchip Camera/ISP team");
> +MODULE_DESCRIPTION("Rockchip MIPI DPHY driver");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.h
> b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.h new file mode 100644
> index 000000000000..c558791064a2
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.h
> @@ -0,0 +1,15 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Rockchip MIPI Synopsys DPHY driver
> + *
> + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
> + */
> +
> +#ifndef __MIPI_DPHY_SY_H__
> +#define __MIPI_DPHY_SY_H__
> +
> +#include <media/v4l2-subdev.h>
> +
> +void rkisp1_set_mipi_dphy_sy_lanes(struct v4l2_subdev *dphy, int lanes);
> +
> +#endif /* __RKISP1_MIPI_DPHY_SY_H__ */
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v10 02/27] clk: davinci: da850-pll: change PLL0 to CLK_OF_DECLARE
From: Sekhar Nori @ 2018-05-16 5:51 UTC (permalink / raw)
To: David Lechner, linux-clk, devicetree, linux-arm-kernel
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
Kevin Hilman, Bartosz Golaszewski, Adam Ford, linux-kernel
In-Reply-To: <88dec9b1-5f4d-a1ac-2b63-b30ae7665851@lechnology.com>
On Tuesday 15 May 2018 09:12 PM, David Lechner wrote:
> On 05/15/2018 08:31 AM, Sekhar Nori wrote:
>> On Wednesday 09 May 2018 10:55 PM, David Lechner wrote:
>>> +void of_da850_pll0_init(struct device_node *node)
>>> {
>>> - return of_davinci_pll_init(dev, dev->of_node, &da850_pll0_info,
>>> - &da850_pll0_obsclk_info,
>>> - da850_pll0_sysclk_info, 7, base, cfgchip);
>>> + void __iomem *base;
>>> + struct regmap *cfgchip;
>>> +
>>> + base = of_iomap(node, 0);
>>> + if (!base) {
>>> + pr_err("%s: ioremap failed\n", __func__);
>>> + return;
>>> + }
>>> +
>>> + cfgchip = syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
>
> In your previous review, you pointed out that the error did not need to
> be handled here because it is handled later in davinci_pll_clk_register().>
> We get a warning there because cfgchip is only needed for unlocking the
> PLL for CPU frequency scaling and is not critical for operation of the
> clocks.
Oops, forgot about that :)
Reviewed-by: Sekhar Nori <nsekhar@ti.com>
Thanks,
Sekhar
^ permalink raw reply
* Re: [PATCH v2 2/2] arm64: dts: exynos: add OF graph between USB-PHY and MUIC
From: Felipe Balbi @ 2018-05-16 5:56 UTC (permalink / raw)
To: Krzysztof Kozlowski, Andrzej Hajda
Cc: open list:DESIGNWARE USB3 DRD IP DRIVER,
Bartlomiej Zolnierkiewicz, Marek Szyprowski,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Greg Kroah-Hartman, Inki Dae, Rob Herring, Mark Rutland,
Chanwoo Choi, Laurent Pinchart, linux-kernel,
linux-samsung-soc@vger.kernel.org
In-Reply-To: <CAJKOXPdxtek3yhr=LoHYwmqoLGPTZtpONR3iOseCi50ZiY=m_Q@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 680 bytes --]
Krzysztof Kozlowski <krzk@kernel.org> writes:
> On Tue, May 15, 2018 at 2:12 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>> OF graph describes USB data lanes between USB-PHY and respective MUIC.
>> Since graph is present and DWC driver can use it to get extcon, obsolete
>> extcon property can be removed.
>>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> ---
>> .../dts/exynos/exynos5433-tm2-common.dtsi | 19 ++++++++++++++++++-
>> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> As we discussed for v1 - since this was not split into two, I'll apply
> it once first patch hits mainline.
I just took patch 1 to my tree, fyi
--
balbi
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply
* [PATCH] ARM: dts: vf610-zii-dev: enable vf610 builtin temp sensor
From: Nikita Yushchenko @ 2018-05-16 6:39 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Stefan Agner,
Rob Herring, Mark Rutland
Cc: linux-arm-kernel, devicetree, linux-kernel, Chris Healy,
Nikita Yushchenko
Vybrid has single internal temperature sensor connected to both internal
ADC modules.
vf610-zii-dev already has ADC0 enabled. Now, to get temperature sensor
captured by iio_hwmon driver, need to configure iio_hwmon node to use
that ADC.
Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
---
arch/arm/boot/dts/vf610-zii-dev.dtsi | 4 ++++
arch/arm/boot/dts/vfxxx.dtsi | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/vf610-zii-dev.dtsi b/arch/arm/boot/dts/vf610-zii-dev.dtsi
index 4890b8a5aa44..5ae5abfe1d55 100644
--- a/arch/arm/boot/dts/vf610-zii-dev.dtsi
+++ b/arch/arm/boot/dts/vf610-zii-dev.dtsi
@@ -222,6 +222,10 @@
status = "okay";
};
+&tempsensor {
+ io-channels = <&adc0 16>;
+};
+
&iomuxc {
pinctrl_adc0_ad5: adc0ad5grp {
fsl,pins = <
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index c3f09b737924..d392794d9c13 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -84,7 +84,7 @@
mask = <0x1000>;
};
- iio-hwmon {
+ tempsensor: iio-hwmon {
compatible = "iio-hwmon";
io-channels = <&adc0 16>, <&adc1 16>;
};
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 4/6] drm/panel: simple: Add support for Banana Pi 7" S070WV20-CT16 panel
From: Chen-Yu Tsai @ 2018-05-16 6:42 UTC (permalink / raw)
To: Jagan Teki
Cc: Mark Rutland, devicetree, Jonathan Liu, Rob Herring,
Maxime Ripard, linux-kernel, dri-devel, David Airlie,
Thierry Reding, linux-arm-kernel
In-Reply-To: <CAMty3ZD7MbvX5eJ9U4QZRSPTXKD3Ps=hQF2hJSsF17YosXFmmg@mail.gmail.com>
On Mon, May 14, 2018 at 11:03 AM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> On Thu, Apr 19, 2018 at 3:02 PM, Chen-Yu Tsai <wens@csie.org> wrote:
>> This panel is marketed as Banana Pi 7" LCD display. On the back is
>> a sticker denoting the model name S070WV20-CT16.
>>
>> This is a 7" 800x480 panel connected through a 24-bit RGB interface.
>> However the panel only does 262k colors.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> .../display/panel/bananapi,s070wv20-ct16.txt | 7 ++++++
>> drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++
>> 2 files changed, 32 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>
>> diff --git a/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>> new file mode 100644
>> index 000000000000..2ec35ce36e9a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>> @@ -0,0 +1,7 @@
>> +Banana Pi 7" (S070WV20-CT16) TFT LCD Panel
>> +
>> +Required properties:
>> +- compatible: should be "bananapi,s070wv20-ct16"
>> +
>> +This binding is compatible with the simple-panel binding, which is specified
>> +in simple-panel.txt in this directory.
>> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
>> index cbf1ab404ee7..9bc037f74d6c 100644
>> --- a/drivers/gpu/drm/panel/panel-simple.c
>> +++ b/drivers/gpu/drm/panel/panel-simple.c
>> @@ -745,6 +745,28 @@ static const struct panel_desc avic_tm070ddh03 = {
>> },
>> };
>>
>> +static const struct drm_display_mode bananapi_s070wv20_ct16_mode = {
>> + .clock = 30000,
>> + .hdisplay = 800,
>> + .hsync_start = 800 + 40,
>> + .hsync_end = 800 + 40 + 48,
>> + .htotal = 800 + 40 + 48 + 40,
>> + .vdisplay = 480,
>> + .vsync_start = 480 + 13,
>> + .vsync_end = 480 + 13 + 3,
>> + .vtotal = 480 + 13 + 3 + 29,
>> +};
>> +
>> +static const struct panel_desc bananapi_s070wv20_ct16 = {
>> + .modes = &bananapi_s070wv20_ct16_mode,
>> + .num_modes = 1,
>> + .bpc = 6,
>> + .size = {
>> + .width = 154,
>> + .height = 86,
>> + },
>> +};
>
> I think this parallel RGB interface right? I too have same display
> with DSI I'm sure these setting will not useful right? do we need to
> write separate panel driver for that?
AFAIK the DSI model is an RGB panel with a MIPI DSI bridge on the
connector board. The model I have is dual interface.
ChenYu
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH net-next v2 15/15] arm64: dts: allwinner: a64: add SRAM controller device tree node
From: Chen-Yu Tsai @ 2018-05-16 6:47 UTC (permalink / raw)
To: Maxime Ripard
Cc: Icenowy Zheng, linux-arm-kernel, Mark Rutland, devicetree,
Stephen Boyd, netdev, Michael Turquette, Rob Herring,
Corentin Labbe, Mark Brown, Giuseppe Cavallaro, linux-clk
In-Reply-To: <20180514080310.ngev5h6cqe4taedl@flea>
On Mon, May 14, 2018 at 1:03 AM, Maxime Ripard
<maxime.ripard@bootlin.com> wrote:
> 1;5201;0c
> On Sun, May 13, 2018 at 12:37:49PM -0700, Chen-Yu Tsai wrote:
>> On Wed, May 2, 2018 at 4:54 AM, Maxime Ripard <maxime.ripard@bootlin.com> wrote:
>> > On Wed, May 02, 2018 at 06:19:51PM +0800, Icenowy Zheng wrote:
>> >>
>> >>
>> >> 于 2018年5月2日 GMT+08:00 下午5:53:21, Chen-Yu Tsai <wens@csie.org> 写到:
>> >> >On Wed, May 2, 2018 at 5:51 PM, Maxime Ripard
>> >> ><maxime.ripard@bootlin.com> wrote:
>> >> >> Hi,
>> >> >>
>> >> >> On Wed, May 02, 2018 at 12:12:27AM +0800, Chen-Yu Tsai wrote:
>> >> >>> From: Icenowy Zheng <icenowy@aosc.io>
>> >> >>>
>> >> >>> Allwinner A64 has a SRAM controller, and in the device tree
>> >> >currently
>> >> >>> we have a syscon node to enable EMAC driver to access the EMAC clock
>> >> >>> register. As SRAM controller driver can now export regmap for this
>> >> >>> register, replace the syscon node to the SRAM controller device
>> >> >node,
>> >> >>> and let EMAC driver to acquire its EMAC clock regmap.
>> >> >>>
>> >> >>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> >> >>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> >> >>> ---
>> >> >>> arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 23
>> >> >+++++++++++++++----
>> >> >>> 1 file changed, 19 insertions(+), 4 deletions(-)
>> >> >>>
>> >> >>> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> >> >b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> >> >>> index 1b2ef28c42bd..1c37659d9d41 100644
>> >> >>> --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> >> >>> +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
>> >> >>> @@ -168,10 +168,25 @@
>> >> >>> #size-cells = <1>;
>> >> >>> ranges;
>> >> >>>
>> >> >>> - syscon: syscon@1c00000 {
>> >> >>> - compatible =
>> >> >"allwinner,sun50i-a64-system-controller",
>> >> >>> - "syscon";
>> >> >>> + sram_controller: sram-controller@1c00000 {
>> >> >>> + compatible =
>> >> >"allwinner,sun50i-a64-sram-controller";
>> >> >>
>> >> >> I don't think there's anything preventing us from keeping the
>> >> >> -system-controller compatible. It's what was in the DT before, and
>> >> >> it's how it's called in the datasheet.
>> >> >
>> >> >I actually meant to ask you about this. The -system-controller
>> >> >compatible matches the datasheet better. Maybe we should just
>> >> >switch to that one?
>> >>
>> >> No, if we do the switch the system-controller compatible,
>> >> the device will be probed on the same memory region with
>> >> a syscon on old DTs.
>> >
>> > The device hasn't magically changed either. Maybe we just need to add
>> > a check to make sure we don't have the syscon compatible in the SRAM
>> > driver probe so that the double driver issue doesn't happen?
>>
>> The syscon interface (which is not even a full blown device driver)
>> only looks at the "syscon" compatible. Either way we're removing that
>> part from the device tree so things should be ok for new device trees.
>> As Maxime mentioned we can do a check for the syscon compatible and
>> either give a warning to the user asking them to update their device
>> tree, or not register our custom regmap, or not probe the SRAM driver.
>> Personally I prefer the first option. The system controller block is
>> probed before any syscon users, so we should be fine, given the dwmac
>> driver goes the custom regmap path first.
>>
>> BTW, I still might end up changing the compatible. The manual uses
>> "system control", not "system controller", which I think makes sense,
>> since it is just a bunch of register files, kind of like the GRF
>> (General Register Files) block found in Rockchip SoCs [1], and not an
>> actual "controller".
>
> I'm not really fond of that, but we should at least make it consistent
> on the other patches Paul sent then.
For the A10s / A13 right?
I think my naming is slightly better, but it's just a minor detail.
While we're still debating this, can I merge the R40 stuff first?
The driver bits are already in.
Thanks
ChenYu
^ permalink raw reply
* Re: [PATCH net-next v2 2/2] drivers: net: Remove device_node checks with of_mdiobus_register()
From: Antoine Tenart @ 2018-05-16 6:49 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, Andrew Lunn, Vivien Didelot, David S. Miller,
Nicolas Ferre, Fugang Duan, Sergei Shtylyov, Giuseppe Cavallaro,
Alexandre Torgue, Jose Abreu, Grygorii Strashko, Woojung Huh,
Microchip Linux Driver Support, Rob Herring, Frank Rowand,
Antoine Tenart, Tobias Jordan, Russell King
In-Reply-To: <20180515235619.27773-3-f.fainelli@gmail.com>
Hi Florian,
On Tue, May 15, 2018 at 04:56:19PM -0700, Florian Fainelli wrote:
> A number of drivers have the following pattern:
>
> if (np)
> of_mdiobus_register()
> else
> mdiobus_register()
>
> which the implementation of of_mdiobus_register() now takes care of.
> Remove that pattern in drivers that strictly adhere to it.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> drivers/net/dsa/bcm_sf2.c | 8 ++------
> drivers/net/dsa/mv88e6xxx/chip.c | 5 +----
> drivers/net/ethernet/cadence/macb_main.c | 12 +++---------
> drivers/net/ethernet/freescale/fec_main.c | 8 ++------
> drivers/net/ethernet/marvell/mvmdio.c | 5 +----
For mvmdio,
Reviewed-by: Antoine Tenart <antoine.tenart@bootlin.com>
Thanks!
Antoine
> drivers/net/ethernet/renesas/sh_eth.c | 11 +++--------
> drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 5 +----
> drivers/net/ethernet/ti/davinci_mdio.c | 8 +++-----
> drivers/net/phy/mdio-gpio.c | 6 +-----
> drivers/net/phy/mdio-mscc-miim.c | 6 +-----
> drivers/net/usb/lan78xx.c | 7 ++-----
> 11 files changed, 20 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
> index ac621f44237a..02e8982519ce 100644
> --- a/drivers/net/dsa/bcm_sf2.c
> +++ b/drivers/net/dsa/bcm_sf2.c
> @@ -450,12 +450,8 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
> priv->slave_mii_bus->parent = ds->dev->parent;
> priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;
>
> - if (dn)
> - err = of_mdiobus_register(priv->slave_mii_bus, dn);
> - else
> - err = mdiobus_register(priv->slave_mii_bus);
> -
> - if (err)
> + err = of_mdiobus_register(priv->slave_mii_bus, dn);
> + if (err && dn)
> of_node_put(dn);
>
> return err;
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
> index b23c11d9f4b2..2bb3f03ee1cb 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -2454,10 +2454,7 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
> return err;
> }
>
> - if (np)
> - err = of_mdiobus_register(bus, np);
> - else
> - err = mdiobus_register(bus);
> + err = of_mdiobus_register(bus, np);
> if (err) {
> dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
> mv88e6xxx_g2_irq_mdio_free(chip, bus);
> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
> index b4c9268100bb..3e93df5d4e3b 100644
> --- a/drivers/net/ethernet/cadence/macb_main.c
> +++ b/drivers/net/ethernet/cadence/macb_main.c
> @@ -591,16 +591,10 @@ static int macb_mii_init(struct macb *bp)
> dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
>
> np = bp->pdev->dev.of_node;
> + if (pdata)
> + bp->mii_bus->phy_mask = pdata->phy_mask;
>
> - if (np) {
> - err = of_mdiobus_register(bp->mii_bus, np);
> - } else {
> - if (pdata)
> - bp->mii_bus->phy_mask = pdata->phy_mask;
> -
> - err = mdiobus_register(bp->mii_bus);
> - }
> -
> + err = of_mdiobus_register(bp->mii_bus, np);
> if (err)
> goto err_out_free_mdiobus;
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index d4604bc8eb5b..f3e43db0d6cb 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -2052,13 +2052,9 @@ static int fec_enet_mii_init(struct platform_device *pdev)
> fep->mii_bus->parent = &pdev->dev;
>
> node = of_get_child_by_name(pdev->dev.of_node, "mdio");
> - if (node) {
> - err = of_mdiobus_register(fep->mii_bus, node);
> + err = of_mdiobus_register(fep->mii_bus, node);
> + if (node)
> of_node_put(node);
> - } else {
> - err = mdiobus_register(fep->mii_bus);
> - }
> -
> if (err)
> goto err_out_free_mdiobus;
>
> diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
> index 0495487f7b42..c5dac6bd2be4 100644
> --- a/drivers/net/ethernet/marvell/mvmdio.c
> +++ b/drivers/net/ethernet/marvell/mvmdio.c
> @@ -348,10 +348,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
> goto out_mdio;
> }
>
> - if (pdev->dev.of_node)
> - ret = of_mdiobus_register(bus, pdev->dev.of_node);
> - else
> - ret = mdiobus_register(bus);
> + ret = of_mdiobus_register(bus, pdev->dev.of_node);
> if (ret < 0) {
> dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
> goto out_mdio;
> diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
> index 5970d9e5ddf1..8dd41e08a6c6 100644
> --- a/drivers/net/ethernet/renesas/sh_eth.c
> +++ b/drivers/net/ethernet/renesas/sh_eth.c
> @@ -3025,15 +3025,10 @@ static int sh_mdio_init(struct sh_eth_private *mdp,
> pdev->name, pdev->id);
>
> /* register MDIO bus */
> - if (dev->of_node) {
> - ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
> - } else {
> - if (pd->phy_irq > 0)
> - mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
> -
> - ret = mdiobus_register(mdp->mii_bus);
> - }
> + if (pd->phy_irq > 0)
> + mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
>
> + ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
> if (ret)
> goto out_free_bus;
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> index f5f37bfa1d58..5df1a608e566 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> @@ -233,10 +233,7 @@ int stmmac_mdio_register(struct net_device *ndev)
> new_bus->phy_mask = mdio_bus_data->phy_mask;
> new_bus->parent = priv->device;
>
> - if (mdio_node)
> - err = of_mdiobus_register(new_bus, mdio_node);
> - else
> - err = mdiobus_register(new_bus);
> + err = of_mdiobus_register(new_bus, mdio_node);
> if (err != 0) {
> dev_err(dev, "Cannot register the MDIO bus\n");
> goto bus_register_fail;
> diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
> index 98a1c97fb95e..8ac72831af05 100644
> --- a/drivers/net/ethernet/ti/davinci_mdio.c
> +++ b/drivers/net/ethernet/ti/davinci_mdio.c
> @@ -429,12 +429,10 @@ static int davinci_mdio_probe(struct platform_device *pdev)
> * defined to support backward compatibility with DTs which assume that
> * Davinci MDIO will always scan the bus for PHYs detection.
> */
> - if (dev->of_node && of_get_child_count(dev->of_node)) {
> + if (dev->of_node && of_get_child_count(dev->of_node))
> data->skip_scan = true;
> - ret = of_mdiobus_register(data->bus, dev->of_node);
> - } else {
> - ret = mdiobus_register(data->bus);
> - }
> +
> + ret = of_mdiobus_register(data->bus, dev->of_node);
> if (ret)
> goto bail_out;
>
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
> index b501221819e1..4e4c8daf44c3 100644
> --- a/drivers/net/phy/mdio-gpio.c
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -179,11 +179,7 @@ static int mdio_gpio_probe(struct platform_device *pdev)
> if (!new_bus)
> return -ENODEV;
>
> - if (pdev->dev.of_node)
> - ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
> - else
> - ret = mdiobus_register(new_bus);
> -
> + ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
> if (ret)
> mdio_gpio_bus_deinit(&pdev->dev);
>
> diff --git a/drivers/net/phy/mdio-mscc-miim.c b/drivers/net/phy/mdio-mscc-miim.c
> index 8c689ccfdbca..badbc99bedd3 100644
> --- a/drivers/net/phy/mdio-mscc-miim.c
> +++ b/drivers/net/phy/mdio-mscc-miim.c
> @@ -151,11 +151,7 @@ static int mscc_miim_probe(struct platform_device *pdev)
> }
> }
>
> - if (pdev->dev.of_node)
> - ret = of_mdiobus_register(bus, pdev->dev.of_node);
> - else
> - ret = mdiobus_register(bus);
> -
> + ret = of_mdiobus_register(bus, pdev->dev.of_node);
> if (ret < 0) {
> dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
> return ret;
> diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
> index 91761436709a..8dff87ec6d99 100644
> --- a/drivers/net/usb/lan78xx.c
> +++ b/drivers/net/usb/lan78xx.c
> @@ -1843,12 +1843,9 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
> }
>
> node = of_get_child_by_name(dev->udev->dev.of_node, "mdio");
> - if (node) {
> - ret = of_mdiobus_register(dev->mdiobus, node);
> + ret = of_mdiobus_register(dev->mdiobus, node);
> + if (node)
> of_node_put(node);
> - } else {
> - ret = mdiobus_register(dev->mdiobus);
> - }
> if (ret) {
> netdev_err(dev->net, "can't register MDIO bus\n");
> goto exit1;
> --
> 2.14.1
>
--
Antoine Ténart, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH] ARM: dts: imx51-zii-rdu1: cleanup eMMC node
From: Nikita Yushchenko @ 2018-05-16 6:53 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Rob Herring, Mark Rutland
Cc: linux-arm-kernel, devicetree, linux-kernel, Chris Healy,
Andrey Smirnov, Nikita Yushchenko
On RDU1, sdhc1 is used for eMMC, and that is 3.3V only.
Thus configure device node not to probe it as SD/SDIO and not try 1.8V.
Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
---
arch/arm/boot/dts/imx51-zii-rdu1.dts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts
index 0c99ac04ad08..ad2a7c9b203e 100644
--- a/arch/arm/boot/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts
@@ -462,7 +462,10 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_esdhc1>;
bus-width = <4>;
+ no-1-8-v;
non-removable;
+ no-sdio;
+ no-sd;
status = "okay";
};
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 2/2] arm64: dts: renesas: initial V3HSK board device tree
From: Simon Horman @ 2018-05-16 7:04 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: Mark Rutland, devicetree, Magnus Damm, Catalin Marinas,
Will Deacon, linux-renesas-soc, Rob Herring, linux-arm-kernel
In-Reply-To: <20180513080704.yeypjjtv7hdmqajt@verge.net.au>
On Sun, May 13, 2018 at 10:07:04AM +0200, Simon Horman wrote:
> On Thu, May 10, 2018 at 09:12:30PM +0300, Sergei Shtylyov wrote:
> > Add the initial device tree for the V3H Starter Kit board.
> > The board has 1 debug serial port (SCIF0); include support for it,
> > so that the serial console can work.
> >
> > Based on the original (and large) patch by Vladimir Barinov.
> >
> > Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
> > Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>
> This looks fine but I will wait to see if there are other reviews before
> applying.
>
> Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Applied
^ permalink raw reply
* Re: [PATCH v2 0/9] Input: support for latest Lenovo thinkpads (series 80)
From: Teika Kazura @ 2018-05-16 7:09 UTC (permalink / raw)
To: aaron.ma, dmitry.torokhov
Cc: benjamin.tissoires, devicetree, linux-input, linux-kernel
In-Reply-To: <ca40347e-44cd-aa93-75ba-1bf0a63705be@canonical.com>
From: Aaron Ma <aaron.ma@canonical.com>
Date: Tue, 17 Apr 2018 19:42:27 +0800
> Could you apply my patch too?
>
> It add LEN0096 that Benjamin's patch doesn't include.
>
> + "LEN0096", /* X280 */
Aaron, in your original patch in last Oct [1], both *LEN0092 and* LEN0096 were aded. Which should be the case, both two, or only LEN0096?
[1] https://www.spinics.net/lists/kernel/msg2625450.html
Teika (Teika kazura)
^ permalink raw reply
* 答复: [PATCH v9 2/5] dt-bindings: scsi: ufs: add document for hisi-ufs
From: liwei (CM) @ 2018-05-16 7:18 UTC (permalink / raw)
To: liwei (CM), Rob Herring
Cc: mark.rutland@arm.com, catalin.marinas@arm.com,
will.deacon@arm.com, yamada.masahiro@socionext.com,
vinholikatti@gmail.com, jejb@linux.vnet.ibm.com,
linux-scsi@vger.kernel.org, khilman@baylibre.com, zangleigang,
krzk@kernel.org, treding@nvidia.com, devicetree@vger.kernel.org,
arnd@arndb.de, Fengbaopeng (kevin, Kirin Solution Dept),
gregory.clement@free-electrons.com,
linux-arm-kernel@lists.infradead.org, thomas.petazzoni
In-Reply-To: <20180424125827.k2dgeu6uon75wzni@rob-hp-laptop>
Hi, Rob & Arnd
Sorry to bother you, do you have any other questions or comments? If not, we will continue to issue patch v10.
Look forward to your reply, thank you!
-----邮件原件-----
发件人: liwei (CM)
发送时间: 2018年4月24日 21:54
收件人: 'Rob Herring'
抄送: mark.rutland@arm.com; catalin.marinas@arm.com; will.deacon@arm.com; vinholikatti@gmail.com; jejb@linux.vnet.ibm.com; martin.petersen@oracle.com; khilman@baylibre.com; arnd@arndb.de; gregory.clement@free-electrons.com; thomas.petazzoni@free-electrons.com; yamada.masahiro@socionext.com; riku.voipio@linaro.org; treding@nvidia.com; krzk@kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-scsi@vger.kernel.org; zangleigang; Gengjianfeng; guodong.xu@linaro.org
主题: 答复: [PATCH v9 2/5] dt-bindings: scsi: ufs: add document for hisi-ufs
Hi, Rob
Thanks for your patience.
Hi, Arnd
From Rob's suggestion, we have to list the properties node in ufs-hisi.txt bingings even if documented in the common binding.
-----邮件原件-----
发件人: Rob Herring [mailto:robh@kernel.org]
发送时间: 2018年4月24日 20:58
收件人: liwei (CM)
抄送: mark.rutland@arm.com; catalin.marinas@arm.com; will.deacon@arm.com; vinholikatti@gmail.com; jejb@linux.vnet.ibm.com; martin.petersen@oracle.com; khilman@baylibre.com; arnd@arndb.de; gregory.clement@free-electrons.com; thomas.petazzoni@free-electrons.com; yamada.masahiro@socionext.com; riku.voipio@linaro.org; treding@nvidia.com; krzk@kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-scsi@vger.kernel.org; zangleigang; Gengjianfeng; guodong.xu@linaro.org
主题: Re: [PATCH v9 2/5] dt-bindings: scsi: ufs: add document for hisi-ufs
On Tue, Apr 17, 2018 at 10:08:11PM +0800, Li Wei wrote:
> add ufs node document for Hisilicon.
>
> Signed-off-by: Li Wei <liwei213@huawei.com>
> ---
> Documentation/devicetree/bindings/ufs/ufs-hisi.txt | 29 ++++++++++++++++++++++
> .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 10 +++++---
> 2 files changed, 36 insertions(+), 3 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/ufs/ufs-hisi.txt
>
> diff --git a/Documentation/devicetree/bindings/ufs/ufs-hisi.txt b/Documentation/devicetree/bindings/ufs/ufs-hisi.txt
> new file mode 100644
> index 000000000000..d49ab7d8f31d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/ufs/ufs-hisi.txt
> @@ -0,0 +1,29 @@
> +* Hisilicon Universal Flash Storage (UFS) Host Controller
> +
> +UFS nodes are defined to describe on-chip UFS hardware macro.
> +Each UFS Host Controller should have its own node.
> +
> +Required properties:
> +- compatible : compatible list, contains one of the following -
> + "hisilicon,hi3660-ufs", "jedec,ufs-1.1" for hisi ufs
> + host controller present on Hi36xx chipset.
> +- reg : should contain UFS register address space & UFS SYS CTRL register address,
> +- interrupt-parent : interrupt device
> +- interrupts : interrupt number
> +- resets : reset node register, the "arst" corresponds to reset the APB/AXI bus.
arst belongs in reset-names.
OK, I will fix it in next patch;
> +- reset-names : describe reset node register
What happened to clocks? You still have to list which ones apply even if
documented in the common binding.
OK, I will fix it in next patch;
> +
> +Example:
> +
> + ufs: ufs@ff3b0000 {
> + compatible = "hisilicon,hi3660-ufs", "jedec,ufs-1.1";
> + /* 0: HCI standard */
> + /* 1: UFS SYS CTRL */
> + reg = <0x0 0xff3b0000 0x0 0x1000>,
> + <0x0 0xff3b1000 0x0 0x1000>;
> + interrupt-parent = <&gic>;
> + interrupts = <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>;
> + /* offset: 0x84; bit: 7 */
> + resets = <&crg_rst 0x84 7>;
> + reset-names = "arst";
> + };
> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> index c39dfef76a18..adcfb79f63f5 100644
> --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> @@ -41,6 +41,8 @@ Optional properties:
> -lanes-per-direction : number of lanes available per direction - either 1 or 2.
> Note that it is assume same number of lanes is used both
> directions at once. If not specified, default is 2 lanes per direction.
> +- resets : reset node register, the "rst" corresponds to reset the whole UFS IP.
> +- reset-names : describe reset node register
Does your controller have 1 or 2 resets? There's no point in adding this
here if it doesn't apply to your controller.
There are 2 reset in our soc init, the "rst" corresponds to reset the whole UFS IP, and " arst " only reset the APB/AXI bus.
Discussed with our soc colleagues that "arst" is assert by default and needs to deassert,but it done in bootloader,so will remove 'arst' in next patch.
About the 'reset' property,it seems that Arnd Bergmann has different suggestion,he suggested that add 'rst' to ufshcd-pltfrm because it seems common.
But it looks like only our soc init needs it. What's your opinion? Does it still needs add to common bindings?
> Note: If above properties are not defined it can be assumed that the supply
> regulators or clocks are always on.
> @@ -61,9 +63,11 @@ Example:
> vccq-max-microamp = 200000;
> vccq2-max-microamp = 200000;
>
> - clocks = <&core 0>, <&ref 0>, <&iface 0>;
> - clock-names = "core_clk", "ref_clk", "iface_clk";
> - freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
> + clocks = <&core 0>, <&ref 0>, <&phy 0>, <&iface 0>;
> + clock-names = "core_clk", "ref_clk", "phy_clk", "iface_clk";
> + freq-table-hz = <100000000 200000000>, <0 0>, <0 0>, <0 0>;
> + resets = <&reset 0 1>;
> + reset-names = "rst";
> phys = <&ufsphy1>;
> phy-names = "ufsphy";
> };
> --
> 2.15.0
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 4/6] drm/panel: simple: Add support for Banana Pi 7" S070WV20-CT16 panel
From: Jagan Teki @ 2018-05-16 7:20 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Maxime Ripard, David Airlie, Thierry Reding, Rob Herring,
Mark Rutland, dri-devel, linux-arm-kernel, linux-kernel,
devicetree, Jonathan Liu
In-Reply-To: <CAGb2v64CASge22O0CviNmgEV0CSFgipkKu86F-6hiaLChPh_EA@mail.gmail.com>
On Wed, May 16, 2018 at 12:12 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Mon, May 14, 2018 at 11:03 AM, Jagan Teki <jagan@amarulasolutions.com> wrote:
>> On Thu, Apr 19, 2018 at 3:02 PM, Chen-Yu Tsai <wens@csie.org> wrote:
>>> This panel is marketed as Banana Pi 7" LCD display. On the back is
>>> a sticker denoting the model name S070WV20-CT16.
>>>
>>> This is a 7" 800x480 panel connected through a 24-bit RGB interface.
>>> However the panel only does 262k colors.
>>>
>>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>> ---
>>> .../display/panel/bananapi,s070wv20-ct16.txt | 7 ++++++
>>> drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++
>>> 2 files changed, 32 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>> new file mode 100644
>>> index 000000000000..2ec35ce36e9a
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/display/panel/bananapi,s070wv20-ct16.txt
>>> @@ -0,0 +1,7 @@
>>> +Banana Pi 7" (S070WV20-CT16) TFT LCD Panel
>>> +
>>> +Required properties:
>>> +- compatible: should be "bananapi,s070wv20-ct16"
>>> +
>>> +This binding is compatible with the simple-panel binding, which is specified
>>> +in simple-panel.txt in this directory.
>>> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
>>> index cbf1ab404ee7..9bc037f74d6c 100644
>>> --- a/drivers/gpu/drm/panel/panel-simple.c
>>> +++ b/drivers/gpu/drm/panel/panel-simple.c
>>> @@ -745,6 +745,28 @@ static const struct panel_desc avic_tm070ddh03 = {
>>> },
>>> };
>>>
>>> +static const struct drm_display_mode bananapi_s070wv20_ct16_mode = {
>>> + .clock = 30000,
>>> + .hdisplay = 800,
>>> + .hsync_start = 800 + 40,
>>> + .hsync_end = 800 + 40 + 48,
>>> + .htotal = 800 + 40 + 48 + 40,
>>> + .vdisplay = 480,
>>> + .vsync_start = 480 + 13,
>>> + .vsync_end = 480 + 13 + 3,
>>> + .vtotal = 480 + 13 + 3 + 29,
>>> +};
>>> +
>>> +static const struct panel_desc bananapi_s070wv20_ct16 = {
>>> + .modes = &bananapi_s070wv20_ct16_mode,
>>> + .num_modes = 1,
>>> + .bpc = 6,
>>> + .size = {
>>> + .width = 154,
>>> + .height = 86,
>>> + },
>>> +};
>>
>> I think this parallel RGB interface right? I too have same display
>> with DSI I'm sure these setting will not useful right? do we need to
>> write separate panel driver for that?
>
> AFAIK the DSI model is an RGB panel with a MIPI DSI bridge on the
> connector board. The model I have is dual interface.
Yes, this is what I have [1] where same strip can use for both RGB and
MIPI DSI. can bananapi,s070wv20-ct16 work for DSI interface as well?
[1] https://www.aliexpress.com/item/New-Arrival-Banana-Pro-Pi-7-inch-LCD-Display-Touch-Screen-Raspberry-Pi-Car-GPS-FreeShipping/32335608836.html
Jagan.
^ permalink raw reply
* RE: [PATCH v5 01/14] dt-bindings: connector: add properties for typec
From: Peter Chen @ 2018-05-16 7:21 UTC (permalink / raw)
To: Jun Li, robh+dt@kernel.org, gregkh@linuxfoundation.org,
heikki.krogerus@linux.intel.com, linux@roeck-us.net
Cc: a.hajda@samsung.com, cw00.choi@samsung.com,
shufan_lee@richtek.com, gsomlo@gmail.com,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
dl-linux-imx
In-Reply-To: <1525307094-27402-2-git-send-email-jun.li@nxp.com>
> Add bingdings supported by current typec driver, so user can pass all those
> properties via dt.
>
%s/bingdings/bindings
Peter
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox