2018-07-20 12:24:02 +05:30
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2018 , The Linux Foundation . All rights reserved .
2020-07-08 14:16:04 +02:00
* datasheet : https : //www.ti.com/lit/ds/symlink/sn65dsi86.pdf
2018-07-20 12:24:02 +05:30
*/
2021-10-25 10:09:25 -07:00
# include <linux/atomic.h>
2021-04-23 09:58:55 -07:00
# include <linux/auxiliary_bus.h>
2021-10-25 10:09:25 -07:00
# include <linux/bitfield.h>
2020-05-07 14:34:55 -07:00
# include <linux/bits.h>
2018-07-20 12:24:02 +05:30
# include <linux/clk.h>
2019-07-02 08:44:17 -07:00
# include <linux/debugfs.h>
2018-07-20 12:24:02 +05:30
# include <linux/gpio/consumer.h>
2020-05-07 14:34:55 -07:00
# include <linux/gpio/driver.h>
2018-07-20 12:24:02 +05:30
# include <linux/i2c.h>
2018-08-13 17:30:42 -04:00
# include <linux/iopoll.h>
2019-05-19 20:36:36 +02:00
# include <linux/module.h>
2018-07-20 12:24:02 +05:30
# include <linux/of_graph.h>
# include <linux/pm_runtime.h>
2021-10-25 10:09:25 -07:00
# include <linux/pwm.h>
2018-07-20 12:24:02 +05:30
# include <linux/regmap.h>
# include <linux/regulator/consumer.h>
2020-11-02 10:11:41 -08:00
# include <asm/unaligned.h>
2022-04-21 09:31:02 +02:00
# include <drm/display/drm_dp_aux_bus.h>
# include <drm/display/drm_dp_helper.h>
2019-05-19 20:36:36 +02:00
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
2019-08-26 17:26:29 +02:00
# include <drm/drm_bridge.h>
2022-02-04 16:13:40 -08:00
# include <drm/drm_bridge_connector.h>
2022-09-19 12:20:08 +02:00
# include <drm/drm_edid.h>
2019-05-19 20:36:36 +02:00
# include <drm/drm_mipi_dsi.h>
# include <drm/drm_of.h>
# include <drm/drm_panel.h>
# include <drm/drm_print.h>
# include <drm/drm_probe_helper.h>
2018-07-20 12:24:02 +05:30
# define SN_DEVICE_REV_REG 0x08
# define SN_DPPLL_SRC_REG 0x0A
2018-08-13 17:30:41 -04:00
# define DPPLL_CLK_SRC_DSICLK BIT(0)
# define REFCLK_FREQ_MASK GENMASK(3, 1)
# define REFCLK_FREQ(x) ((x) << 1)
# define DPPLL_SRC_DP_PLL_LOCK BIT(7)
# define SN_PLL_ENABLE_REG 0x0D
2018-07-20 12:24:02 +05:30
# define SN_DSI_LANES_REG 0x10
2018-08-13 17:30:41 -04:00
# define CHA_DSI_LANES_MASK GENMASK(4, 3)
# define CHA_DSI_LANES(x) ((x) << 3)
2018-07-20 12:24:02 +05:30
# define SN_DSIA_CLK_FREQ_REG 0x12
# define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG 0x20
# define SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG 0x24
# define SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG 0x2C
# define SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG 0x2D
2018-08-13 17:30:41 -04:00
# define CHA_HSYNC_POLARITY BIT(7)
2018-07-20 12:24:02 +05:30
# define SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG 0x30
# define SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG 0x31
2018-08-13 17:30:41 -04:00
# define CHA_VSYNC_POLARITY BIT(7)
2018-07-20 12:24:02 +05:30
# define SN_CHA_HORIZONTAL_BACK_PORCH_REG 0x34
# define SN_CHA_VERTICAL_BACK_PORCH_REG 0x36
# define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38
# define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A
2020-05-18 11:47:17 -07:00
# define SN_LN_ASSIGN_REG 0x59
# define LN_ASSIGN_WIDTH 2
2018-08-13 17:30:41 -04:00
# define SN_ENH_FRAME_REG 0x5A
# define VSTREAM_ENABLE BIT(3)
2020-05-18 11:47:17 -07:00
# define LN_POLRS_OFFSET 4
# define LN_POLRS_MASK 0xf0
2018-07-20 12:24:02 +05:30
# define SN_DATA_FORMAT_REG 0x5B
2019-12-18 14:35:27 -08:00
# define BPP_18_RGB BIT(0)
2018-08-13 17:30:41 -04:00
# define SN_HPD_DISABLE_REG 0x5C
# define HPD_DISABLE BIT(0)
2022-09-19 12:20:08 +02:00
# define HPD_DEBOUNCED_STATE BIT(4)
2020-05-07 14:34:55 -07:00
# define SN_GPIO_IO_REG 0x5E
# define SN_GPIO_INPUT_SHIFT 4
# define SN_GPIO_OUTPUT_SHIFT 0
# define SN_GPIO_CTRL_REG 0x5F
# define SN_GPIO_MUX_INPUT 0
# define SN_GPIO_MUX_OUTPUT 1
# define SN_GPIO_MUX_SPECIAL 2
# define SN_GPIO_MUX_MASK 0x3
2018-08-13 17:30:42 -04:00
# define SN_AUX_WDATA_REG(x) (0x64 + (x))
2018-08-13 17:30:41 -04:00
# define SN_AUX_ADDR_19_16_REG 0x74
# define SN_AUX_ADDR_15_8_REG 0x75
# define SN_AUX_ADDR_7_0_REG 0x76
2020-11-02 10:11:41 -08:00
# define SN_AUX_ADDR_MASK GENMASK(19, 0)
2018-08-13 17:30:41 -04:00
# define SN_AUX_LENGTH_REG 0x77
# define SN_AUX_CMD_REG 0x78
2018-11-30 14:57:45 +05:30
# define AUX_CMD_SEND BIT(0)
2018-08-13 17:30:41 -04:00
# define AUX_CMD_REQ(x) ((x) << 4)
2018-08-13 17:30:42 -04:00
# define SN_AUX_RDATA_REG(x) (0x79 + (x))
2018-08-13 17:30:41 -04:00
# define SN_SSC_CONFIG_REG 0x93
# define DP_NUM_LANES_MASK GENMASK(5, 4)
# define DP_NUM_LANES(x) ((x) << 4)
# define SN_DATARATE_CONFIG_REG 0x94
# define DP_DATARATE_MASK GENMASK(7, 5)
# define DP_DATARATE(x) ((x) << 5)
2022-08-31 11:26:52 +03:00
# define SN_TRAINING_SETTING_REG 0x95
# define SCRAMBLE_DISABLE BIT(4)
2018-08-13 17:30:41 -04:00
# define SN_ML_TX_MODE_REG 0x96
# define ML_TX_MAIN_LINK_OFF 0
# define ML_TX_NORMAL_MODE BIT(0)
2021-10-25 10:09:25 -07:00
# define SN_PWM_PRE_DIV_REG 0xA0
# define SN_BACKLIGHT_SCALE_REG 0xA1
# define BACKLIGHT_SCALE_MAX 0xFFFF
# define SN_BACKLIGHT_REG 0xA3
# define SN_PWM_EN_INV_REG 0xA5
# define SN_PWM_INV_MASK BIT(0)
# define SN_PWM_EN_MASK BIT(1)
2018-08-13 17:30:42 -04:00
# define SN_AUX_CMD_STATUS_REG 0xF4
# define AUX_IRQ_STATUS_AUX_RPLY_TOUT BIT(3)
# define AUX_IRQ_STATUS_AUX_SHORT BIT(5)
# define AUX_IRQ_STATUS_NAT_I2C_FAIL BIT(6)
2018-07-20 12:24:02 +05:30
# define MIN_DSI_CLK_FREQ_MHZ 40
/* fudge factor required to account for 8b/10b encoding */
# define DP_CLK_FUDGE_NUM 10
# define DP_CLK_FUDGE_DEN 8
2018-08-13 17:30:42 -04:00
/* Matches DP_AUX_MAX_PAYLOAD_BYTES (for now) */
# define SN_AUX_MAX_PAYLOAD_BYTES 16
2018-07-20 12:24:02 +05:30
# define SN_REGULATOR_SUPPLY_NUM 4
2020-05-18 11:47:17 -07:00
# define SN_MAX_DP_LANES 4
2020-05-07 14:34:55 -07:00
# define SN_NUM_GPIOS 4
# define SN_GPIO_PHYSICAL_OFFSET 1
2020-10-02 14:03:51 -07:00
# define SN_LINK_TRAINING_TRIES 10
2021-10-25 10:09:25 -07:00
# define SN_PWM_GPIO_IDX 3 /* 4th GPIO */
2020-05-07 14:34:55 -07:00
/**
2021-04-23 09:58:48 -07:00
* struct ti_sn65dsi86 - Platform data for ti - sn65dsi86 driver .
2021-04-23 09:58:55 -07:00
* @ bridge_aux : AUX - bus sub device for MIPI - to - eDP bridge functionality .
* @ gpio_aux : AUX - bus sub device for GPIO controller functionality .
2021-06-11 10:17:43 -07:00
* @ aux_aux : AUX - bus sub device for eDP AUX channel functionality .
2021-10-25 10:09:25 -07:00
* @ pwm_aux : AUX - bus sub device for PWM controller functionality .
2021-04-23 09:58:55 -07:00
*
* @ dev : Pointer to the top level ( i2c ) device .
2020-05-07 14:34:55 -07:00
* @ regmap : Regmap for accessing i2c .
* @ aux : Our aux channel .
* @ bridge : Our bridge .
* @ connector : Our connector .
* @ host_node : Remote DSI node .
* @ dsi : Our MIPI DSI source .
* @ refclk : Our reference clock .
2021-06-24 03:03:02 +03:00
* @ next_bridge : The bridge on the eDP side .
2020-05-07 14:34:55 -07:00
* @ enable_gpio : The GPIO we toggle to enable the bridge .
* @ supplies : Data for bulk enabling / disabling our regulators .
* @ dp_lanes : Count of dp_lanes we ' re using .
2020-05-18 11:47:17 -07:00
* @ ln_assign : Value to program to the LN_ASSIGN register .
2020-06-12 12:30:49 -07:00
* @ ln_polrs : Value for the 4 - bit LN_POLRS field of SN_ENH_FRAME_REG .
2021-04-23 09:58:59 -07:00
* @ comms_enabled : If true then communication over the aux channel is enabled .
* @ comms_mutex : Protects modification of comms_enabled .
2020-05-07 14:34:55 -07:00
*
* @ gchip : If we expose our GPIOs , this is used .
* @ gchip_output : A cache of whether we ' ve set GPIOs to output . This
* serves double - duty of keeping track of the direction and
* also keeping track of whether we ' ve incremented the
* pm_runtime reference count for this pin , which we do
* whenever a pin is configured as an output . This is a
* bitmap so we can do atomic ops on it without an extra
* lock so concurrent users of our 4 GPIOs don ' t stomp on
* each other ' s read - modify - write .
2021-10-25 10:09:25 -07:00
*
* @ pchip : pwm_chip if the PWM is exposed .
* @ pwm_enabled : Used to track if the PWM signal is currently enabled .
* @ pwm_pin_busy : Track if GPIO4 is currently requested for GPIO or PWM .
* @ pwm_refclk_freq : Cache for the reference clock input to the PWM .
2020-05-07 14:34:55 -07:00
*/
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 {
2021-04-23 09:58:55 -07:00
struct auxiliary_device bridge_aux ;
struct auxiliary_device gpio_aux ;
2021-06-11 10:17:43 -07:00
struct auxiliary_device aux_aux ;
2021-10-25 10:09:25 -07:00
struct auxiliary_device pwm_aux ;
2021-04-23 09:58:55 -07:00
2018-07-20 12:24:02 +05:30
struct device * dev ;
struct regmap * regmap ;
2018-08-13 17:30:42 -04:00
struct drm_dp_aux aux ;
2018-07-20 12:24:02 +05:30
struct drm_bridge bridge ;
2022-02-04 16:13:40 -08:00
struct drm_connector * connector ;
2018-07-20 12:24:02 +05:30
struct device_node * host_node ;
struct mipi_dsi_device * dsi ;
struct clk * refclk ;
2021-06-24 03:03:02 +03:00
struct drm_bridge * next_bridge ;
2018-07-20 12:24:02 +05:30
struct gpio_desc * enable_gpio ;
struct regulator_bulk_data supplies [ SN_REGULATOR_SUPPLY_NUM ] ;
2019-12-18 14:35:24 -08:00
int dp_lanes ;
2020-05-18 11:47:17 -07:00
u8 ln_assign ;
u8 ln_polrs ;
2021-04-23 09:58:59 -07:00
bool comms_enabled ;
struct mutex comms_mutex ;
2020-05-07 14:34:55 -07:00
2020-06-12 12:30:47 -07:00
# if defined(CONFIG_OF_GPIO)
2020-05-07 14:34:55 -07:00
struct gpio_chip gchip ;
DECLARE_BITMAP ( gchip_output , SN_NUM_GPIOS ) ;
2020-06-12 12:30:47 -07:00
# endif
2021-10-25 10:09:25 -07:00
# if defined(CONFIG_PWM)
struct pwm_chip pchip ;
bool pwm_enabled ;
atomic_t pwm_pin_busy ;
# endif
unsigned int pwm_refclk_freq ;
2018-07-20 12:24:02 +05:30
} ;
2021-04-23 09:58:49 -07:00
static const struct regmap_range ti_sn65dsi86_volatile_ranges [ ] = {
2018-07-20 12:24:02 +05:30
{ . range_min = 0 , . range_max = 0xFF } ,
} ;
static const struct regmap_access_table ti_sn_bridge_volatile_table = {
2021-04-23 09:58:49 -07:00
. yes_ranges = ti_sn65dsi86_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( ti_sn65dsi86_volatile_ranges ) ,
2018-07-20 12:24:02 +05:30
} ;
2021-04-23 09:58:49 -07:00
static const struct regmap_config ti_sn65dsi86_regmap_config = {
2018-07-20 12:24:02 +05:30
. reg_bits = 8 ,
. val_bits = 8 ,
. volatile_table = & ti_sn_bridge_volatile_table ,
. cache_type = REGCACHE_NONE ,
2021-12-14 16:25:29 -08:00
. max_register = 0xFF ,
2018-07-20 12:24:02 +05:30
} ;
2021-10-28 09:35:48 -07:00
static int __maybe_unused ti_sn65dsi86_read_u16 ( struct ti_sn65dsi86 * pdata ,
unsigned int reg , u16 * val )
2021-10-25 10:09:25 -07:00
{
u8 buf [ 2 ] ;
int ret ;
ret = regmap_bulk_read ( pdata - > regmap , reg , buf , ARRAY_SIZE ( buf ) ) ;
if ( ret )
return ret ;
* val = buf [ 0 ] | ( buf [ 1 ] < < 8 ) ;
return 0 ;
}
2021-04-23 09:58:49 -07:00
static void ti_sn65dsi86_write_u16 ( struct ti_sn65dsi86 * pdata ,
2018-07-20 12:24:02 +05:30
unsigned int reg , u16 val )
{
2021-10-25 10:09:24 -07:00
u8 buf [ 2 ] = { val & 0xff , val > > 8 } ;
regmap_bulk_write ( pdata - > regmap , reg , buf , ARRAY_SIZE ( buf ) ) ;
2018-07-20 12:24:02 +05:30
}
2021-04-23 09:58:58 -07:00
static u32 ti_sn_bridge_get_dsi_freq ( struct ti_sn65dsi86 * pdata )
{
u32 bit_rate_khz , clk_freq_khz ;
struct drm_display_mode * mode =
& pdata - > bridge . encoder - > crtc - > state - > adjusted_mode ;
bit_rate_khz = mode - > clock *
mipi_dsi_pixel_format_to_bpp ( pdata - > dsi - > format ) ;
clk_freq_khz = bit_rate_khz / ( pdata - > dsi - > lanes * 2 ) ;
return clk_freq_khz ;
}
/* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */
static const u32 ti_sn_bridge_refclk_lut [ ] = {
12000000 ,
19200000 ,
26000000 ,
27000000 ,
38400000 ,
} ;
/* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */
static const u32 ti_sn_bridge_dsiclk_lut [ ] = {
468000000 ,
384000000 ,
416000000 ,
486000000 ,
460800000 ,
} ;
static void ti_sn_bridge_set_refclk_freq ( struct ti_sn65dsi86 * pdata )
{
int i ;
u32 refclk_rate ;
const u32 * refclk_lut ;
size_t refclk_lut_size ;
if ( pdata - > refclk ) {
refclk_rate = clk_get_rate ( pdata - > refclk ) ;
refclk_lut = ti_sn_bridge_refclk_lut ;
refclk_lut_size = ARRAY_SIZE ( ti_sn_bridge_refclk_lut ) ;
clk_prepare_enable ( pdata - > refclk ) ;
} else {
refclk_rate = ti_sn_bridge_get_dsi_freq ( pdata ) * 1000 ;
refclk_lut = ti_sn_bridge_dsiclk_lut ;
refclk_lut_size = ARRAY_SIZE ( ti_sn_bridge_dsiclk_lut ) ;
}
/* for i equals to refclk_lut_size means default frequency */
for ( i = 0 ; i < refclk_lut_size ; i + + )
if ( refclk_lut [ i ] = = refclk_rate )
break ;
regmap_update_bits ( pdata - > regmap , SN_DPPLL_SRC_REG , REFCLK_FREQ_MASK ,
REFCLK_FREQ ( i ) ) ;
2021-10-25 10:09:25 -07:00
/*
* The PWM refclk is based on the value written to SN_DPPLL_SRC_REG ,
* regardless of its actual sourcing .
*/
pdata - > pwm_refclk_freq = ti_sn_bridge_refclk_lut [ i ] ;
2021-04-23 09:58:58 -07:00
}
2021-04-23 09:58:59 -07:00
static void ti_sn65dsi86_enable_comms ( struct ti_sn65dsi86 * pdata )
{
mutex_lock ( & pdata - > comms_mutex ) ;
/* configure bridge ref_clk */
ti_sn_bridge_set_refclk_freq ( pdata ) ;
/*
* HPD on this bridge chip is a bit useless . This is an eDP bridge
* so the HPD is an internal signal that ' s only there to signal that
* the panel is done powering up . . . . but the bridge chip debounces
* this signal by between 100 ms and 400 ms ( depending on process ,
* voltage , and temperate - - I measured it at about 200 ms ) . One
* particular panel asserted HPD 84 ms after it was powered on meaning
* that we saw HPD 284 ms after power on . . . . but the same panel said
* that instead of looking at HPD you could just hardcode a delay of
* 200 ms . We ' ll assume that the panel driver will have the hardcoded
* delay in its prepare and always disable HPD .
*
* If HPD somehow makes sense on some future panel we ' ll have to
* change this to be conditional on someone specifying that HPD should
* be used .
*/
regmap_update_bits ( pdata - > regmap , SN_HPD_DISABLE_REG , HPD_DISABLE ,
HPD_DISABLE ) ;
pdata - > comms_enabled = true ;
mutex_unlock ( & pdata - > comms_mutex ) ;
}
static void ti_sn65dsi86_disable_comms ( struct ti_sn65dsi86 * pdata )
{
mutex_lock ( & pdata - > comms_mutex ) ;
pdata - > comms_enabled = false ;
clk_disable_unprepare ( pdata - > refclk ) ;
mutex_unlock ( & pdata - > comms_mutex ) ;
}
2021-04-23 09:58:49 -07:00
static int __maybe_unused ti_sn65dsi86_resume ( struct device * dev )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( dev ) ;
2018-07-20 12:24:02 +05:30
int ret ;
ret = regulator_bulk_enable ( SN_REGULATOR_SUPPLY_NUM , pdata - > supplies ) ;
if ( ret ) {
DRM_ERROR ( " failed to enable supplies %d \n " , ret ) ;
return ret ;
}
2021-07-30 08:46:02 -07:00
/* td2: min 100 us after regulators before enabling the GPIO */
usleep_range ( 100 , 110 ) ;
2018-07-20 12:24:02 +05:30
gpiod_set_value ( pdata - > enable_gpio , 1 ) ;
2021-04-23 09:58:59 -07:00
/*
* If we have a reference clock we can enable communication w / the
* panel ( including the aux channel ) w / out any need for an input clock
* so we can do it in resume which lets us read the EDID before
* pre_enable ( ) . Without a reference clock we need the MIPI reference
* clock so reading early doesn ' t work .
*/
if ( pdata - > refclk )
ti_sn65dsi86_enable_comms ( pdata ) ;
2018-07-20 12:24:02 +05:30
return ret ;
}
2021-04-23 09:58:49 -07:00
static int __maybe_unused ti_sn65dsi86_suspend ( struct device * dev )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( dev ) ;
2018-07-20 12:24:02 +05:30
int ret ;
2021-04-23 09:58:59 -07:00
if ( pdata - > refclk )
ti_sn65dsi86_disable_comms ( pdata ) ;
2018-07-20 12:24:02 +05:30
gpiod_set_value ( pdata - > enable_gpio , 0 ) ;
ret = regulator_bulk_disable ( SN_REGULATOR_SUPPLY_NUM , pdata - > supplies ) ;
if ( ret )
DRM_ERROR ( " failed to disable supplies %d \n " , ret ) ;
return ret ;
}
2021-04-23 09:58:49 -07:00
static const struct dev_pm_ops ti_sn65dsi86_pm_ops = {
SET_RUNTIME_PM_OPS ( ti_sn65dsi86_suspend , ti_sn65dsi86_resume , NULL )
2020-06-09 17:34:55 +05:30
SET_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend ,
pm_runtime_force_resume )
2018-07-20 12:24:02 +05:30
} ;
2019-07-02 08:44:17 -07:00
static int status_show ( struct seq_file * s , void * data )
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = s - > private ;
2019-07-02 08:44:17 -07:00
unsigned int reg , val ;
seq_puts ( s , " STATUS REGISTERS: \n " ) ;
pm_runtime_get_sync ( pdata - > dev ) ;
/* IRQ Status Registers, see Table 31 in datasheet */
for ( reg = 0xf0 ; reg < = 0xf8 ; reg + + ) {
regmap_read ( pdata - > regmap , reg , & val ) ;
seq_printf ( s , " [0x%02x] = 0x%08x \n " , reg , val ) ;
}
2021-04-23 09:58:57 -07:00
pm_runtime_put_autosuspend ( pdata - > dev ) ;
2019-07-02 08:44:17 -07:00
return 0 ;
}
DEFINE_SHOW_ATTRIBUTE ( status ) ;
2021-04-23 09:58:51 -07:00
static void ti_sn65dsi86_debugfs_remove ( void * data )
2019-07-02 08:44:17 -07:00
{
2021-04-23 09:58:51 -07:00
debugfs_remove_recursive ( data ) ;
2019-07-02 08:44:17 -07:00
}
2021-04-23 09:58:51 -07:00
static void ti_sn65dsi86_debugfs_init ( struct ti_sn65dsi86 * pdata )
2019-07-02 08:44:17 -07:00
{
2021-04-23 09:58:51 -07:00
struct device * dev = pdata - > dev ;
struct dentry * debugfs ;
int ret ;
debugfs = debugfs_create_dir ( dev_name ( dev ) , NULL ) ;
/*
* We might get an error back if debugfs wasn ' t enabled in the kernel
* so let ' s just silently return upon failure .
*/
if ( IS_ERR_OR_NULL ( debugfs ) )
return ;
ret = devm_add_action_or_reset ( dev , ti_sn65dsi86_debugfs_remove , debugfs ) ;
if ( ret )
return ;
debugfs_create_file ( " status " , 0600 , debugfs , pdata , & status_fops ) ;
2019-07-02 08:44:17 -07:00
}
2021-06-24 03:03:03 +03:00
/* -----------------------------------------------------------------------------
* Auxiliary Devices ( * not * AUX )
*/
static void ti_sn65dsi86_uninit_aux ( void * data )
{
auxiliary_device_uninit ( data ) ;
}
static void ti_sn65dsi86_delete_aux ( void * data )
{
auxiliary_device_delete ( data ) ;
}
/*
* AUX bus docs say that a non - NULL release is mandatory , but it makes no
* sense for the model used here where all of the aux devices are allocated
* in the single shared structure . We ' ll use this noop as a workaround .
*/
static void ti_sn65dsi86_noop ( struct device * dev ) { }
static int ti_sn65dsi86_add_aux_device ( struct ti_sn65dsi86 * pdata ,
struct auxiliary_device * aux ,
const char * name )
{
struct device * dev = pdata - > dev ;
int ret ;
aux - > name = name ;
aux - > dev . parent = dev ;
aux - > dev . release = ti_sn65dsi86_noop ;
device_set_of_node_from_dev ( & aux - > dev , dev ) ;
ret = auxiliary_device_init ( aux ) ;
if ( ret )
return ret ;
ret = devm_add_action_or_reset ( dev , ti_sn65dsi86_uninit_aux , aux ) ;
if ( ret )
return ret ;
ret = auxiliary_device_add ( aux ) ;
if ( ret )
return ret ;
ret = devm_add_action_or_reset ( dev , ti_sn65dsi86_delete_aux , aux ) ;
return ret ;
}
/* -----------------------------------------------------------------------------
* AUX Adapter
*/
static struct ti_sn65dsi86 * aux_to_ti_sn65dsi86 ( struct drm_dp_aux * aux )
{
return container_of ( aux , struct ti_sn65dsi86 , aux ) ;
}
static ssize_t ti_sn_aux_transfer ( struct drm_dp_aux * aux ,
struct drm_dp_aux_msg * msg )
{
struct ti_sn65dsi86 * pdata = aux_to_ti_sn65dsi86 ( aux ) ;
u32 request = msg - > request & ~ ( DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE ) ;
u32 request_val = AUX_CMD_REQ ( msg - > request ) ;
u8 * buf = msg - > buffer ;
unsigned int len = msg - > size ;
unsigned int val ;
int ret ;
u8 addr_len [ SN_AUX_LENGTH_REG + 1 - SN_AUX_ADDR_19_16_REG ] ;
if ( len > SN_AUX_MAX_PAYLOAD_BYTES )
return - EINVAL ;
pm_runtime_get_sync ( pdata - > dev ) ;
mutex_lock ( & pdata - > comms_mutex ) ;
/*
* If someone tries to do a DDC over AUX transaction before pre_enable ( )
* on a device without a dedicated reference clock then we just can ' t
* do it . Fail right away . This prevents non - refclk users from reading
* the EDID before enabling the panel but such is life .
*/
if ( ! pdata - > comms_enabled ) {
ret = - EIO ;
goto exit ;
}
switch ( request ) {
case DP_AUX_NATIVE_WRITE :
case DP_AUX_I2C_WRITE :
case DP_AUX_NATIVE_READ :
case DP_AUX_I2C_READ :
regmap_write ( pdata - > regmap , SN_AUX_CMD_REG , request_val ) ;
/* Assume it's good */
msg - > reply = 0 ;
break ;
default :
ret = - EINVAL ;
goto exit ;
}
BUILD_BUG_ON ( sizeof ( addr_len ) ! = sizeof ( __be32 ) ) ;
put_unaligned_be32 ( ( msg - > address & SN_AUX_ADDR_MASK ) < < 8 | len ,
addr_len ) ;
regmap_bulk_write ( pdata - > regmap , SN_AUX_ADDR_19_16_REG , addr_len ,
ARRAY_SIZE ( addr_len ) ) ;
if ( request = = DP_AUX_NATIVE_WRITE | | request = = DP_AUX_I2C_WRITE )
regmap_bulk_write ( pdata - > regmap , SN_AUX_WDATA_REG ( 0 ) , buf , len ) ;
/* Clear old status bits before start so we don't get confused */
regmap_write ( pdata - > regmap , SN_AUX_CMD_STATUS_REG ,
AUX_IRQ_STATUS_NAT_I2C_FAIL |
AUX_IRQ_STATUS_AUX_RPLY_TOUT |
AUX_IRQ_STATUS_AUX_SHORT ) ;
regmap_write ( pdata - > regmap , SN_AUX_CMD_REG , request_val | AUX_CMD_SEND ) ;
/* Zero delay loop because i2c transactions are slow already */
ret = regmap_read_poll_timeout ( pdata - > regmap , SN_AUX_CMD_REG , val ,
! ( val & AUX_CMD_SEND ) , 0 , 50 * 1000 ) ;
if ( ret )
goto exit ;
ret = regmap_read ( pdata - > regmap , SN_AUX_CMD_STATUS_REG , & val ) ;
if ( ret )
goto exit ;
if ( val & AUX_IRQ_STATUS_AUX_RPLY_TOUT ) {
/*
* The hardware tried the message seven times per the DP spec
* but it hit a timeout . We ignore defers here because they ' re
* handled in hardware .
*/
ret = - ETIMEDOUT ;
goto exit ;
}
if ( val & AUX_IRQ_STATUS_AUX_SHORT ) {
ret = regmap_read ( pdata - > regmap , SN_AUX_LENGTH_REG , & len ) ;
if ( ret )
goto exit ;
} else if ( val & AUX_IRQ_STATUS_NAT_I2C_FAIL ) {
switch ( request ) {
case DP_AUX_I2C_WRITE :
case DP_AUX_I2C_READ :
msg - > reply | = DP_AUX_I2C_REPLY_NACK ;
break ;
case DP_AUX_NATIVE_READ :
case DP_AUX_NATIVE_WRITE :
msg - > reply | = DP_AUX_NATIVE_REPLY_NACK ;
break ;
}
len = 0 ;
goto exit ;
}
if ( request ! = DP_AUX_NATIVE_WRITE & & request ! = DP_AUX_I2C_WRITE & & len ! = 0 )
ret = regmap_bulk_read ( pdata - > regmap , SN_AUX_RDATA_REG ( 0 ) , buf , len ) ;
exit :
mutex_unlock ( & pdata - > comms_mutex ) ;
pm_runtime_mark_last_busy ( pdata - > dev ) ;
pm_runtime_put_autosuspend ( pdata - > dev ) ;
if ( ret )
return ret ;
return len ;
}
static int ti_sn_aux_probe ( struct auxiliary_device * adev ,
const struct auxiliary_device_id * id )
{
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( adev - > dev . parent ) ;
int ret ;
pdata - > aux . name = " ti-sn65dsi86-aux " ;
pdata - > aux . dev = & adev - > dev ;
pdata - > aux . transfer = ti_sn_aux_transfer ;
drm_dp_aux_init ( & pdata - > aux ) ;
ret = devm_of_dp_aux_populate_ep_devices ( & pdata - > aux ) ;
if ( ret )
return ret ;
/*
* The eDP to MIPI bridge parts don ' t work until the AUX channel is
* setup so we don ' t add it in the main driver probe , we add it now .
*/
return ti_sn65dsi86_add_aux_device ( pdata , & pdata - > bridge_aux , " bridge " ) ;
}
static const struct auxiliary_device_id ti_sn_aux_id_table [ ] = {
{ . name = " ti_sn65dsi86.aux " , } ,
{ } ,
} ;
static struct auxiliary_driver ti_sn_aux_driver = {
. name = " aux " ,
. probe = ti_sn_aux_probe ,
. id_table = ti_sn_aux_id_table ,
} ;
/*------------------------------------------------------------------------------
* DRM Bridge
*/
2021-04-23 09:58:49 -07:00
static struct ti_sn65dsi86 * bridge_to_ti_sn65dsi86 ( struct drm_bridge * bridge )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:48 -07:00
return container_of ( bridge , struct ti_sn65dsi86 , bridge ) ;
2018-07-20 12:24:02 +05:30
}
2021-10-25 17:15:32 +02:00
static int ti_sn_attach_host ( struct ti_sn65dsi86 * pdata )
2018-07-20 12:24:02 +05:30
{
2021-12-07 13:57:52 -08:00
int val ;
2018-07-20 12:24:02 +05:30
struct mipi_dsi_host * host ;
struct mipi_dsi_device * dsi ;
2021-10-25 17:15:31 +02:00
struct device * dev = pdata - > dev ;
2018-07-20 12:24:02 +05:30
const struct mipi_dsi_device_info info = { . type = " ti_sn_bridge " ,
. channel = 0 ,
. node = NULL ,
2021-10-25 17:15:32 +02:00
} ;
2021-02-19 16:53:02 -05:00
2018-07-20 12:24:02 +05:30
host = of_find_mipi_dsi_host_by_node ( pdata - > host_node ) ;
2021-12-07 13:57:52 -08:00
if ( ! host )
return - EPROBE_DEFER ;
2018-07-20 12:24:02 +05:30
2021-10-25 17:15:31 +02:00
dsi = devm_mipi_dsi_device_register_full ( dev , host , & info ) ;
2021-12-07 13:57:52 -08:00
if ( IS_ERR ( dsi ) )
2021-10-25 17:15:32 +02:00
return PTR_ERR ( dsi ) ;
2018-07-20 12:24:02 +05:30
2019-12-18 14:35:26 -08:00
/* TODO: setting to 4 MIPI lanes always for now */
2018-07-20 12:24:02 +05:30
dsi - > lanes = 4 ;
dsi - > format = MIPI_DSI_FMT_RGB888 ;
2019-07-02 08:44:18 -07:00
dsi - > mode_flags = MIPI_DSI_MODE_VIDEO ;
2018-07-20 12:24:02 +05:30
/* check if continuous dsi clock is required or not */
2021-10-25 17:15:31 +02:00
pm_runtime_get_sync ( dev ) ;
2018-07-20 12:24:02 +05:30
regmap_read ( pdata - > regmap , SN_DPPLL_SRC_REG , & val ) ;
2021-10-25 17:15:31 +02:00
pm_runtime_put_autosuspend ( dev ) ;
2018-07-20 12:24:02 +05:30
if ( ! ( val & DPPLL_CLK_SRC_DSICLK ) )
dsi - > mode_flags | = MIPI_DSI_CLOCK_NON_CONTINUOUS ;
2021-10-25 17:15:32 +02:00
pdata - > dsi = dsi ;
2021-12-07 13:57:52 -08:00
return devm_mipi_dsi_attach ( dev , dsi ) ;
2021-10-25 17:15:32 +02:00
}
static int ti_sn_bridge_attach ( struct drm_bridge * bridge ,
enum drm_bridge_attach_flags flags )
{
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
int ret ;
pdata - > aux . drm_dev = bridge - > dev ;
ret = drm_dp_aux_register ( & pdata - > aux ) ;
if ( ret < 0 ) {
drm_err ( bridge - > dev , " Failed to register DP AUX channel: %d \n " , ret ) ;
return ret ;
}
2022-07-11 12:21:17 +03:00
/*
* Attach the next bridge .
* We never want the next bridge to * also * create a connector .
*/
2021-06-24 03:03:02 +03:00
ret = drm_bridge_attach ( bridge - > encoder , pdata - > next_bridge ,
2022-07-11 12:21:17 +03:00
& pdata - > bridge , flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR ) ;
2021-06-24 03:03:02 +03:00
if ( ret < 0 )
2022-02-04 16:13:40 -08:00
goto err_initted_aux ;
2022-07-11 12:21:17 +03:00
if ( flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR )
return 0 ;
2022-02-04 16:13:40 -08:00
pdata - > connector = drm_bridge_connector_init ( pdata - > bridge . dev ,
pdata - > bridge . encoder ) ;
if ( IS_ERR ( pdata - > connector ) ) {
ret = PTR_ERR ( pdata - > connector ) ;
goto err_initted_aux ;
}
drm_connector_attach_encoder ( pdata - > connector , pdata - > bridge . encoder ) ;
2021-06-24 03:03:02 +03:00
2018-07-20 12:24:02 +05:30
return 0 ;
2022-02-04 16:13:40 -08:00
err_initted_aux :
2021-02-19 16:53:02 -05:00
drm_dp_aux_unregister ( & pdata - > aux ) ;
2018-07-20 12:24:02 +05:30
return ret ;
}
2021-02-19 16:53:02 -05:00
static void ti_sn_bridge_detach ( struct drm_bridge * bridge )
{
2021-04-23 09:58:49 -07:00
drm_dp_aux_unregister ( & bridge_to_ti_sn65dsi86 ( bridge ) - > aux ) ;
2021-02-19 16:53:02 -05:00
}
2021-09-20 15:57:59 -07:00
static enum drm_mode_status
ti_sn_bridge_mode_valid ( struct drm_bridge * bridge ,
const struct drm_display_info * info ,
const struct drm_display_mode * mode )
{
/* maximum supported resolution is 4K at 60 fps */
if ( mode - > clock > 594000 )
return MODE_CLOCK_HIGH ;
2022-08-31 11:26:51 +03:00
/*
* The front and back porch registers are 8 bits , and pulse width
* registers are 15 bits , so reject any modes with larger periods .
*/
if ( ( mode - > hsync_start - mode - > hdisplay ) > 0xff )
return MODE_HBLANK_WIDE ;
if ( ( mode - > vsync_start - mode - > vdisplay ) > 0xff )
return MODE_VBLANK_WIDE ;
if ( ( mode - > hsync_end - mode - > hsync_start ) > 0x7fff )
return MODE_HSYNC_WIDE ;
if ( ( mode - > vsync_end - mode - > vsync_start ) > 0x7fff )
return MODE_VSYNC_WIDE ;
if ( ( mode - > htotal - mode - > hsync_end ) > 0xff )
return MODE_HBLANK_WIDE ;
if ( ( mode - > vtotal - mode - > vsync_end ) > 0xff )
return MODE_VBLANK_WIDE ;
2021-09-20 15:57:59 -07:00
return MODE_OK ;
}
2022-07-03 22:27:24 +02:00
static void ti_sn_bridge_atomic_disable ( struct drm_bridge * bridge ,
struct drm_bridge_state * old_bridge_state )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:49 -07:00
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
2018-07-20 12:24:02 +05:30
/* disable video stream */
2018-08-13 17:30:41 -04:00
regmap_update_bits ( pdata - > regmap , SN_ENH_FRAME_REG , VSTREAM_ENABLE , 0 ) ;
2018-07-20 12:24:02 +05:30
}
2021-04-23 09:58:48 -07:00
static void ti_sn_bridge_set_dsi_rate ( struct ti_sn65dsi86 * pdata )
2019-12-18 14:35:22 -08:00
{
unsigned int bit_rate_mhz , clk_freq_mhz ;
unsigned int val ;
struct drm_display_mode * mode =
& pdata - > bridge . encoder - > crtc - > state - > adjusted_mode ;
/* set DSIA clk frequency */
bit_rate_mhz = ( mode - > clock / 1000 ) *
mipi_dsi_pixel_format_to_bpp ( pdata - > dsi - > format ) ;
clk_freq_mhz = bit_rate_mhz / ( pdata - > dsi - > lanes * 2 ) ;
/* for each increment in val, frequency increases by 5MHz */
val = ( MIN_DSI_CLK_FREQ_MHZ / 5 ) +
( ( ( clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ ) / 5 ) & 0xFF ) ;
regmap_write ( pdata - > regmap , SN_DSIA_CLK_FREQ_REG , val ) ;
}
2022-07-11 12:21:16 +03:00
static unsigned int ti_sn_bridge_get_bpp ( struct drm_connector * connector )
2019-12-18 14:35:27 -08:00
{
2022-07-11 12:21:16 +03:00
if ( connector - > display_info . bpc < = 6 )
2019-12-18 14:35:27 -08:00
return 18 ;
else
return 24 ;
}
2020-06-12 12:30:48 -07:00
/*
2018-07-20 12:24:02 +05:30
* LUT index corresponds to register value and
* LUT values corresponds to dp data rate supported
* by the bridge in Mbps unit .
*/
static const unsigned int ti_sn_bridge_dp_rate_lut [ ] = {
0 , 1620 , 2160 , 2430 , 2700 , 3240 , 4320 , 5400
} ;
2022-07-11 12:21:16 +03:00
static int ti_sn_bridge_calc_min_dp_rate_idx ( struct ti_sn65dsi86 * pdata , unsigned int bpp )
2018-07-20 12:24:02 +05:30
{
2019-12-18 14:35:27 -08:00
unsigned int bit_rate_khz , dp_rate_mhz ;
2019-12-18 14:35:22 -08:00
unsigned int i ;
2018-07-20 12:24:02 +05:30
struct drm_display_mode * mode =
& pdata - > bridge . encoder - > crtc - > state - > adjusted_mode ;
2019-12-18 14:35:27 -08:00
/* Calculate minimum bit rate based on our pixel clock. */
2022-07-11 12:21:16 +03:00
bit_rate_khz = mode - > clock * bpp ;
2018-07-20 12:24:02 +05:30
2019-12-18 14:35:24 -08:00
/* Calculate minimum DP data rate, taking 80% as per DP spec */
2019-12-18 14:35:27 -08:00
dp_rate_mhz = DIV_ROUND_UP ( bit_rate_khz * DP_CLK_FUDGE_NUM ,
1000 * pdata - > dp_lanes * DP_CLK_FUDGE_DEN ) ;
2019-12-18 14:35:24 -08:00
2019-12-18 14:35:23 -08:00
for ( i = 1 ; i < ARRAY_SIZE ( ti_sn_bridge_dp_rate_lut ) - 1 ; i + + )
2020-05-04 21:32:29 -07:00
if ( ti_sn_bridge_dp_rate_lut [ i ] > = dp_rate_mhz )
2018-07-20 12:24:02 +05:30
break ;
2019-12-18 14:35:29 -08:00
return i ;
}
2021-06-24 03:03:01 +03:00
static unsigned int ti_sn_bridge_read_valid_rates ( struct ti_sn65dsi86 * pdata )
2019-12-18 14:35:29 -08:00
{
2021-06-24 03:03:01 +03:00
unsigned int valid_rates = 0 ;
2019-12-18 14:35:30 -08:00
unsigned int rate_per_200khz ;
unsigned int rate_mhz ;
u8 dpcd_val ;
2019-12-18 14:35:29 -08:00
int ret ;
2019-12-18 14:35:30 -08:00
int i , j ;
ret = drm_dp_dpcd_readb ( & pdata - > aux , DP_EDP_DPCD_REV , & dpcd_val ) ;
if ( ret ! = 1 ) {
DRM_DEV_ERROR ( pdata - > dev ,
" Can't read eDP rev (%d), assuming 1.1 \n " , ret ) ;
dpcd_val = DP_EDP_11 ;
}
if ( dpcd_val > = DP_EDP_14 ) {
/* eDP 1.4 devices must provide a custom table */
__le16 sink_rates [ DP_MAX_SUPPORTED_RATES ] ;
ret = drm_dp_dpcd_read ( & pdata - > aux , DP_SUPPORTED_LINK_RATES ,
sink_rates , sizeof ( sink_rates ) ) ;
if ( ret ! = sizeof ( sink_rates ) ) {
DRM_DEV_ERROR ( pdata - > dev ,
" Can't read supported rate table (%d) \n " , ret ) ;
/* By zeroing we'll fall back to DP_MAX_LINK_RATE. */
memset ( sink_rates , 0 , sizeof ( sink_rates ) ) ;
}
for ( i = 0 ; i < ARRAY_SIZE ( sink_rates ) ; i + + ) {
rate_per_200khz = le16_to_cpu ( sink_rates [ i ] ) ;
if ( ! rate_per_200khz )
break ;
rate_mhz = rate_per_200khz * 200 / 1000 ;
for ( j = 0 ;
j < ARRAY_SIZE ( ti_sn_bridge_dp_rate_lut ) ;
j + + ) {
if ( ti_sn_bridge_dp_rate_lut [ j ] = = rate_mhz )
2021-06-24 03:03:01 +03:00
valid_rates | = BIT ( j ) ;
2019-12-18 14:35:30 -08:00
}
}
for ( i = 0 ; i < ARRAY_SIZE ( ti_sn_bridge_dp_rate_lut ) ; i + + ) {
2021-06-24 03:03:01 +03:00
if ( valid_rates & BIT ( i ) )
return valid_rates ;
2019-12-18 14:35:30 -08:00
}
DRM_DEV_ERROR ( pdata - > dev ,
" No matching eDP rates in table; falling back \n " ) ;
}
2019-12-18 14:35:29 -08:00
2019-12-18 14:35:30 -08:00
/* On older versions best we can do is use DP_MAX_LINK_RATE */
ret = drm_dp_dpcd_readb ( & pdata - > aux , DP_MAX_LINK_RATE , & dpcd_val ) ;
2019-12-18 14:35:29 -08:00
if ( ret ! = 1 ) {
DRM_DEV_ERROR ( pdata - > dev ,
" Can't read max rate (%d); assuming 5.4 GHz \n " ,
ret ) ;
2019-12-18 14:35:30 -08:00
dpcd_val = DP_LINK_BW_5_4 ;
2019-12-18 14:35:29 -08:00
}
2019-12-18 14:35:30 -08:00
switch ( dpcd_val ) {
default :
DRM_DEV_ERROR ( pdata - > dev ,
" Unexpected max rate (%#x); assuming 5.4 GHz \n " ,
( int ) dpcd_val ) ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2019-12-18 14:35:29 -08:00
case DP_LINK_BW_5_4 :
2021-06-24 03:03:01 +03:00
valid_rates | = BIT ( 7 ) ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2019-12-18 14:35:30 -08:00
case DP_LINK_BW_2_7 :
2021-06-24 03:03:01 +03:00
valid_rates | = BIT ( 4 ) ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2019-12-18 14:35:30 -08:00
case DP_LINK_BW_1_62 :
2021-06-24 03:03:01 +03:00
valid_rates | = BIT ( 1 ) ;
2019-12-18 14:35:30 -08:00
break ;
2019-12-18 14:35:29 -08:00
}
2021-06-24 03:03:01 +03:00
return valid_rates ;
2018-07-20 12:24:02 +05:30
}
2021-04-23 09:58:48 -07:00
static void ti_sn_bridge_set_video_timings ( struct ti_sn65dsi86 * pdata )
2018-07-20 12:24:02 +05:30
{
struct drm_display_mode * mode =
& pdata - > bridge . encoder - > crtc - > state - > adjusted_mode ;
u8 hsync_polarity = 0 , vsync_polarity = 0 ;
if ( mode - > flags & DRM_MODE_FLAG_PHSYNC )
2018-08-13 17:30:41 -04:00
hsync_polarity = CHA_HSYNC_POLARITY ;
2018-07-20 12:24:02 +05:30
if ( mode - > flags & DRM_MODE_FLAG_PVSYNC )
2018-08-13 17:30:41 -04:00
vsync_polarity = CHA_VSYNC_POLARITY ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:49 -07:00
ti_sn65dsi86_write_u16 ( pdata , SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG ,
2018-07-20 12:24:02 +05:30
mode - > hdisplay ) ;
2021-04-23 09:58:49 -07:00
ti_sn65dsi86_write_u16 ( pdata , SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG ,
2018-07-20 12:24:02 +05:30
mode - > vdisplay ) ;
regmap_write ( pdata - > regmap , SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG ,
( mode - > hsync_end - mode - > hsync_start ) & 0xFF ) ;
regmap_write ( pdata - > regmap , SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG ,
( ( ( mode - > hsync_end - mode - > hsync_start ) > > 8 ) & 0x7F ) |
hsync_polarity ) ;
regmap_write ( pdata - > regmap , SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG ,
( mode - > vsync_end - mode - > vsync_start ) & 0xFF ) ;
regmap_write ( pdata - > regmap , SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG ,
( ( ( mode - > vsync_end - mode - > vsync_start ) > > 8 ) & 0x7F ) |
vsync_polarity ) ;
regmap_write ( pdata - > regmap , SN_CHA_HORIZONTAL_BACK_PORCH_REG ,
( mode - > htotal - mode - > hsync_end ) & 0xFF ) ;
regmap_write ( pdata - > regmap , SN_CHA_VERTICAL_BACK_PORCH_REG ,
( mode - > vtotal - mode - > vsync_end ) & 0xFF ) ;
regmap_write ( pdata - > regmap , SN_CHA_HORIZONTAL_FRONT_PORCH_REG ,
( mode - > hsync_start - mode - > hdisplay ) & 0xFF ) ;
regmap_write ( pdata - > regmap , SN_CHA_VERTICAL_FRONT_PORCH_REG ,
( mode - > vsync_start - mode - > vdisplay ) & 0xFF ) ;
usleep_range ( 10000 , 10500 ) ; /* 10ms delay recommended by spec */
}
2021-04-23 09:58:48 -07:00
static unsigned int ti_sn_get_max_lanes ( struct ti_sn65dsi86 * pdata )
2019-12-18 14:35:26 -08:00
{
u8 data ;
int ret ;
ret = drm_dp_dpcd_readb ( & pdata - > aux , DP_MAX_LANE_COUNT , & data ) ;
if ( ret ! = 1 ) {
DRM_DEV_ERROR ( pdata - > dev ,
" Can't read lane count (%d); assuming 4 \n " , ret ) ;
return 4 ;
}
return data & DP_LANE_COUNT_MASK ;
}
2021-04-23 09:58:48 -07:00
static int ti_sn_link_training ( struct ti_sn65dsi86 * pdata , int dp_rate_idx ,
2019-12-18 14:35:29 -08:00
const char * * last_err_str )
2019-12-18 14:35:28 -08:00
{
unsigned int val ;
int ret ;
2020-10-02 14:03:51 -07:00
int i ;
2019-12-18 14:35:28 -08:00
/* set dp clk frequency value */
2019-12-18 14:35:29 -08:00
regmap_update_bits ( pdata - > regmap , SN_DATARATE_CONFIG_REG ,
DP_DATARATE_MASK , DP_DATARATE ( dp_rate_idx ) ) ;
2019-12-18 14:35:28 -08:00
/* enable DP PLL */
regmap_write ( pdata - > regmap , SN_PLL_ENABLE_REG , 1 ) ;
ret = regmap_read_poll_timeout ( pdata - > regmap , SN_DPPLL_SRC_REG , val ,
val & DPPLL_SRC_DP_PLL_LOCK , 1000 ,
50 * 1000 ) ;
if ( ret ) {
2019-12-18 14:35:29 -08:00
* last_err_str = " DP_PLL_LOCK polling failed " ;
2019-12-18 14:35:28 -08:00
goto exit ;
}
2020-10-02 14:03:51 -07:00
/*
* We ' ll try to link train several times . As part of link training
* the bridge chip will write DP_SET_POWER_D0 to DP_SET_POWER . If
* the panel isn ' t ready quite it might respond NAK here which means
* we need to try again .
*/
for ( i = 0 ; i < SN_LINK_TRAINING_TRIES ; i + + ) {
/* Semi auto link training mode */
regmap_write ( pdata - > regmap , SN_ML_TX_MODE_REG , 0x0A ) ;
ret = regmap_read_poll_timeout ( pdata - > regmap , SN_ML_TX_MODE_REG , val ,
val = = ML_TX_MAIN_LINK_OFF | |
val = = ML_TX_NORMAL_MODE , 1000 ,
500 * 1000 ) ;
if ( ret ) {
* last_err_str = " Training complete polling failed " ;
} else if ( val = = ML_TX_MAIN_LINK_OFF ) {
* last_err_str = " Link training failed, link is off " ;
ret = - EIO ;
continue ;
}
break ;
2019-12-18 14:35:28 -08:00
}
2020-10-02 14:03:51 -07:00
/* If we saw quite a few retries, add a note about it */
if ( ! ret & & i > SN_LINK_TRAINING_TRIES / 2 )
DRM_DEV_INFO ( pdata - > dev , " Link training needed %d retries \n " , i ) ;
2019-12-18 14:35:28 -08:00
exit :
/* Disable the PLL if we failed */
if ( ret )
regmap_write ( pdata - > regmap , SN_PLL_ENABLE_REG , 0 ) ;
return ret ;
}
2022-07-03 22:27:24 +02:00
static void ti_sn_bridge_atomic_enable ( struct drm_bridge * bridge ,
struct drm_bridge_state * old_bridge_state )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:49 -07:00
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
2022-07-11 12:21:16 +03:00
struct drm_connector * connector ;
2019-12-18 14:35:29 -08:00
const char * last_err_str = " No supported DP rate " ;
2021-06-24 03:03:01 +03:00
unsigned int valid_rates ;
2019-12-18 14:35:29 -08:00
int dp_rate_idx ;
2018-07-20 12:24:02 +05:30
unsigned int val ;
2019-12-18 14:35:29 -08:00
int ret = - EINVAL ;
2020-05-18 11:47:17 -07:00
int max_dp_lanes ;
2022-07-11 12:21:16 +03:00
unsigned int bpp ;
connector = drm_atomic_get_new_connector_for_encoder ( old_bridge_state - > base . state ,
bridge - > encoder ) ;
if ( ! connector ) {
dev_err_ratelimited ( pdata - > dev , " Could not get the connector \n " ) ;
return ;
}
2018-07-20 12:24:02 +05:30
2020-05-18 11:47:17 -07:00
max_dp_lanes = ti_sn_get_max_lanes ( pdata ) ;
pdata - > dp_lanes = min ( pdata - > dp_lanes , max_dp_lanes ) ;
2019-12-18 14:35:26 -08:00
2018-07-20 12:24:02 +05:30
/* DSI_A lane config */
2020-05-18 11:47:17 -07:00
val = CHA_DSI_LANES ( SN_MAX_DP_LANES - pdata - > dsi - > lanes ) ;
2018-07-20 12:24:02 +05:30
regmap_update_bits ( pdata - > regmap , SN_DSI_LANES_REG ,
2018-08-13 17:30:41 -04:00
CHA_DSI_LANES_MASK , val ) ;
2018-07-20 12:24:02 +05:30
2020-05-18 11:47:17 -07:00
regmap_write ( pdata - > regmap , SN_LN_ASSIGN_REG , pdata - > ln_assign ) ;
regmap_update_bits ( pdata - > regmap , SN_ENH_FRAME_REG , LN_POLRS_MASK ,
pdata - > ln_polrs < < LN_POLRS_OFFSET ) ;
2019-12-18 14:35:28 -08:00
/* set dsi clk frequency value */
2019-12-18 14:35:22 -08:00
ti_sn_bridge_set_dsi_rate ( pdata ) ;
2018-07-20 12:24:02 +05:30
2021-04-16 15:39:26 -07:00
/*
2018-07-20 12:24:02 +05:30
* The SN65DSI86 only supports ASSR Display Authentication method and
2022-08-31 11:26:52 +03:00
* this method is enabled for eDP panels . An eDP panel must support this
2018-07-20 12:24:02 +05:30
* authentication method . We need to enable this method in the eDP panel
* at DisplayPort address 0x0010A prior to link training .
2022-08-31 11:26:52 +03:00
*
* As only ASSR is supported by SN65DSI86 , for full DisplayPort displays
* we need to disable the scrambler .
2018-07-20 12:24:02 +05:30
*/
2022-08-31 11:26:52 +03:00
if ( pdata - > bridge . type = = DRM_MODE_CONNECTOR_eDP ) {
drm_dp_dpcd_writeb ( & pdata - > aux , DP_EDP_CONFIGURATION_SET ,
DP_ALTERNATE_SCRAMBLER_RESET_ENABLE ) ;
regmap_update_bits ( pdata - > regmap , SN_TRAINING_SETTING_REG ,
SCRAMBLE_DISABLE , 0 ) ;
} else {
regmap_update_bits ( pdata - > regmap , SN_TRAINING_SETTING_REG ,
SCRAMBLE_DISABLE , SCRAMBLE_DISABLE ) ;
}
2018-07-20 12:24:02 +05:30
2022-07-11 12:21:16 +03:00
bpp = ti_sn_bridge_get_bpp ( connector ) ;
2019-12-18 14:35:28 -08:00
/* Set the DP output format (18 bpp or 24 bpp) */
2022-07-11 12:21:16 +03:00
val = bpp = = 18 ? BPP_18_RGB : 0 ;
2019-12-18 14:35:28 -08:00
regmap_update_bits ( pdata - > regmap , SN_DATA_FORMAT_REG , BPP_18_RGB , val ) ;
/* DP lane config */
val = DP_NUM_LANES ( min ( pdata - > dp_lanes , 3 ) ) ;
regmap_update_bits ( pdata - > regmap , SN_SSC_CONFIG_REG , DP_NUM_LANES_MASK ,
val ) ;
2021-06-24 03:03:01 +03:00
valid_rates = ti_sn_bridge_read_valid_rates ( pdata ) ;
2019-12-18 14:35:30 -08:00
2019-12-18 14:35:29 -08:00
/* Train until we run out of rates */
2022-07-11 12:21:16 +03:00
for ( dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx ( pdata , bpp ) ;
2019-12-18 14:35:30 -08:00
dp_rate_idx < ARRAY_SIZE ( ti_sn_bridge_dp_rate_lut ) ;
2019-12-18 14:35:29 -08:00
dp_rate_idx + + ) {
2021-06-24 03:03:01 +03:00
if ( ! ( valid_rates & BIT ( dp_rate_idx ) ) )
2019-12-18 14:35:30 -08:00
continue ;
2019-12-18 14:35:29 -08:00
ret = ti_sn_link_training ( pdata , dp_rate_idx , & last_err_str ) ;
if ( ! ret )
break ;
}
if ( ret ) {
DRM_DEV_ERROR ( pdata - > dev , " %s (%d) \n " , last_err_str , ret ) ;
2018-08-13 17:30:45 -04:00
return ;
2019-12-18 14:35:29 -08:00
}
2018-07-20 12:24:02 +05:30
/* config video parameters */
ti_sn_bridge_set_video_timings ( pdata ) ;
/* enable video stream */
2018-08-13 17:30:41 -04:00
regmap_update_bits ( pdata - > regmap , SN_ENH_FRAME_REG , VSTREAM_ENABLE ,
VSTREAM_ENABLE ) ;
2018-07-20 12:24:02 +05:30
}
2022-07-03 22:27:24 +02:00
static void ti_sn_bridge_atomic_pre_enable ( struct drm_bridge * bridge ,
struct drm_bridge_state * old_bridge_state )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:49 -07:00
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
2018-07-20 12:24:02 +05:30
pm_runtime_get_sync ( pdata - > dev ) ;
2021-04-23 09:58:59 -07:00
if ( ! pdata - > refclk )
ti_sn65dsi86_enable_comms ( pdata ) ;
2021-07-30 08:46:02 -07:00
/* td7: min 100 us after enable before DSI data */
usleep_range ( 100 , 110 ) ;
2018-07-20 12:24:02 +05:30
}
2022-07-03 22:27:24 +02:00
static void ti_sn_bridge_atomic_post_disable ( struct drm_bridge * bridge ,
struct drm_bridge_state * old_bridge_state )
2018-07-20 12:24:02 +05:30
{
2021-04-23 09:58:49 -07:00
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
2018-07-20 12:24:02 +05:30
2021-07-30 08:46:01 -07:00
/* semi auto link training mode OFF */
regmap_write ( pdata - > regmap , SN_ML_TX_MODE_REG , 0 ) ;
/* Num lanes to 0 as per power sequencing in data sheet */
regmap_update_bits ( pdata - > regmap , SN_SSC_CONFIG_REG , DP_NUM_LANES_MASK , 0 ) ;
/* disable DP PLL */
regmap_write ( pdata - > regmap , SN_PLL_ENABLE_REG , 0 ) ;
2021-04-23 09:58:59 -07:00
if ( ! pdata - > refclk )
ti_sn65dsi86_disable_comms ( pdata ) ;
2018-07-20 12:24:02 +05:30
pm_runtime_put_sync ( pdata - > dev ) ;
}
2022-09-19 12:20:08 +02:00
static enum drm_connector_status ti_sn_bridge_detect ( struct drm_bridge * bridge )
{
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
int val = 0 ;
pm_runtime_get_sync ( pdata - > dev ) ;
regmap_read ( pdata - > regmap , SN_HPD_DISABLE_REG , & val ) ;
pm_runtime_put_autosuspend ( pdata - > dev ) ;
return val & HPD_DEBOUNCED_STATE ? connector_status_connected
: connector_status_disconnected ;
}
static struct edid * ti_sn_bridge_get_edid ( struct drm_bridge * bridge ,
struct drm_connector * connector )
{
struct ti_sn65dsi86 * pdata = bridge_to_ti_sn65dsi86 ( bridge ) ;
return drm_get_edid ( connector , & pdata - > aux . ddc ) ;
}
2018-07-20 12:24:02 +05:30
static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
. attach = ti_sn_bridge_attach ,
2021-02-19 16:53:02 -05:00
. detach = ti_sn_bridge_detach ,
2021-09-20 15:57:59 -07:00
. mode_valid = ti_sn_bridge_mode_valid ,
2022-09-19 12:20:08 +02:00
. get_edid = ti_sn_bridge_get_edid ,
. detect = ti_sn_bridge_detect ,
2022-07-03 22:27:24 +02:00
. atomic_pre_enable = ti_sn_bridge_atomic_pre_enable ,
. atomic_enable = ti_sn_bridge_atomic_enable ,
. atomic_disable = ti_sn_bridge_atomic_disable ,
. atomic_post_disable = ti_sn_bridge_atomic_post_disable ,
. atomic_reset = drm_atomic_helper_bridge_reset ,
. atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_bridge_destroy_state ,
2018-07-20 12:24:02 +05:30
} ;
2021-06-24 03:03:03 +03:00
static void ti_sn_bridge_parse_lanes ( struct ti_sn65dsi86 * pdata ,
struct device_node * np )
2018-08-13 17:30:42 -04:00
{
2021-06-24 03:03:03 +03:00
u32 lane_assignments [ SN_MAX_DP_LANES ] = { 0 , 1 , 2 , 3 } ;
u32 lane_polarities [ SN_MAX_DP_LANES ] = { } ;
struct device_node * endpoint ;
u8 ln_assign = 0 ;
u8 ln_polrs = 0 ;
int dp_lanes ;
int i ;
2021-04-23 09:58:59 -07:00
/*
2021-06-24 03:03:03 +03:00
* Read config from the device tree about lane remapping and lane
* polarities . These are optional and we assume identity map and
* normal polarity if nothing is specified . It ' s OK to specify just
* data - lanes but not lane - polarities but not vice versa .
*
* Error checking is light ( we just make sure we don ' t crash or
* buffer overrun ) and we assume dts is well formed and specifying
* mappings that the hardware supports .
*/
endpoint = of_graph_get_endpoint_by_regs ( np , 1 , - 1 ) ;
2022-05-24 03:05:20 +02:00
dp_lanes = drm_of_get_data_lanes_count ( endpoint , 1 , SN_MAX_DP_LANES ) ;
if ( dp_lanes > 0 ) {
2021-06-24 03:03:03 +03:00
of_property_read_u32_array ( endpoint , " data-lanes " ,
lane_assignments , dp_lanes ) ;
of_property_read_u32_array ( endpoint , " lane-polarities " ,
lane_polarities , dp_lanes ) ;
} else {
dp_lanes = SN_MAX_DP_LANES ;
2018-08-13 17:30:42 -04:00
}
2021-06-24 03:03:03 +03:00
of_node_put ( endpoint ) ;
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
/*
* Convert into register format . Loop over all lanes even if
* data - lanes had fewer elements so that we nicely initialize
* the LN_ASSIGN register .
*/
for ( i = SN_MAX_DP_LANES - 1 ; i > = 0 ; i - - ) {
ln_assign = ln_assign < < LN_ASSIGN_WIDTH | lane_assignments [ i ] ;
ln_polrs = ln_polrs < < 1 | lane_polarities [ i ] ;
}
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
/* Stash in our struct for when we power on */
pdata - > dp_lanes = dp_lanes ;
pdata - > ln_assign = ln_assign ;
pdata - > ln_polrs = ln_polrs ;
}
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
static int ti_sn_bridge_parse_dsi_host ( struct ti_sn65dsi86 * pdata )
{
struct device_node * np = pdata - > dev - > of_node ;
2020-05-08 16:33:29 -07:00
2021-06-24 03:03:03 +03:00
pdata - > host_node = of_graph_get_remote_node ( np , 0 , 0 ) ;
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
if ( ! pdata - > host_node ) {
DRM_ERROR ( " remote dsi host node not found \n " ) ;
return - ENODEV ;
}
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
return 0 ;
}
2020-11-02 10:11:44 -08:00
2021-06-24 03:03:03 +03:00
static int ti_sn_bridge_probe ( struct auxiliary_device * adev ,
const struct auxiliary_device_id * id )
{
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( adev - > dev . parent ) ;
struct device_node * np = pdata - > dev - > of_node ;
int ret ;
2020-11-02 10:11:44 -08:00
2022-02-28 19:39:54 +01:00
pdata - > next_bridge = devm_drm_of_get_bridge ( pdata - > dev , np , 1 , 0 ) ;
2022-07-22 09:47:55 +02:00
if ( IS_ERR ( pdata - > next_bridge ) )
return dev_err_probe ( pdata - > dev , PTR_ERR ( pdata - > next_bridge ) ,
" failed to create panel bridge \n " ) ;
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
ti_sn_bridge_parse_lanes ( pdata , np ) ;
2018-08-13 17:30:42 -04:00
2021-06-24 03:03:03 +03:00
ret = ti_sn_bridge_parse_dsi_host ( pdata ) ;
2021-05-18 12:19:30 +03:00
if ( ret )
return ret ;
2021-06-24 03:03:03 +03:00
pdata - > bridge . funcs = & ti_sn_bridge_funcs ;
pdata - > bridge . of_node = np ;
2022-08-31 11:26:52 +03:00
pdata - > bridge . type = pdata - > next_bridge - > type = = DRM_MODE_CONNECTOR_DisplayPort
? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP ;
2021-06-24 03:03:03 +03:00
2022-09-19 12:20:08 +02:00
if ( pdata - > bridge . type = = DRM_MODE_CONNECTOR_DisplayPort )
pdata - > bridge . ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT ;
2021-06-24 03:03:03 +03:00
drm_bridge_add ( & pdata - > bridge ) ;
2021-10-25 17:15:32 +02:00
ret = ti_sn_attach_host ( pdata ) ;
2021-12-07 13:57:52 -08:00
if ( ret ) {
dev_err_probe ( pdata - > dev , ret , " failed to attach dsi host \n " ) ;
2021-10-25 17:15:32 +02:00
goto err_remove_bridge ;
2021-12-07 13:57:52 -08:00
}
2021-10-25 17:15:32 +02:00
2021-06-24 03:03:03 +03:00
return 0 ;
2021-10-25 17:15:32 +02:00
err_remove_bridge :
drm_bridge_remove ( & pdata - > bridge ) ;
return ret ;
2018-08-13 17:30:42 -04:00
}
2021-06-24 03:03:03 +03:00
static void ti_sn_bridge_remove ( struct auxiliary_device * adev )
2018-07-20 12:24:02 +05:30
{
2021-06-24 03:03:03 +03:00
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( adev - > dev . parent ) ;
2018-07-20 12:24:02 +05:30
2021-06-24 03:03:03 +03:00
if ( ! pdata )
return ;
2018-07-20 12:24:02 +05:30
2021-06-24 03:03:03 +03:00
drm_bridge_remove ( & pdata - > bridge ) ;
of_node_put ( pdata - > host_node ) ;
2018-07-20 12:24:02 +05:30
}
2021-06-24 03:03:03 +03:00
static const struct auxiliary_device_id ti_sn_bridge_id_table [ ] = {
{ . name = " ti_sn65dsi86.bridge " , } ,
{ } ,
} ;
static struct auxiliary_driver ti_sn_bridge_driver = {
. name = " bridge " ,
. probe = ti_sn_bridge_probe ,
. remove = ti_sn_bridge_remove ,
. id_table = ti_sn_bridge_id_table ,
} ;
/* -----------------------------------------------------------------------------
2021-10-25 10:09:25 -07:00
* PWM Controller
2021-06-24 03:03:03 +03:00
*/
2021-10-25 10:09:25 -07:00
# if defined(CONFIG_PWM)
static int ti_sn_pwm_pin_request ( struct ti_sn65dsi86 * pdata )
{
return atomic_xchg ( & pdata - > pwm_pin_busy , 1 ) ? - EBUSY : 0 ;
}
static void ti_sn_pwm_pin_release ( struct ti_sn65dsi86 * pdata )
{
atomic_set ( & pdata - > pwm_pin_busy , 0 ) ;
}
static struct ti_sn65dsi86 * pwm_chip_to_ti_sn_bridge ( struct pwm_chip * chip )
{
return container_of ( chip , struct ti_sn65dsi86 , pchip ) ;
}
static int ti_sn_pwm_request ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct ti_sn65dsi86 * pdata = pwm_chip_to_ti_sn_bridge ( chip ) ;
2021-06-24 03:03:03 +03:00
2021-10-25 10:09:25 -07:00
return ti_sn_pwm_pin_request ( pdata ) ;
}
static void ti_sn_pwm_free ( struct pwm_chip * chip , struct pwm_device * pwm )
{
struct ti_sn65dsi86 * pdata = pwm_chip_to_ti_sn_bridge ( chip ) ;
ti_sn_pwm_pin_release ( pdata ) ;
}
/*
* Limitations :
* - The PWM signal is not driven when the chip is powered down , or in its
* reset state and the driver does not implement the " suspend state "
* described in the documentation . In order to save power , state - > enabled is
* interpreted as denoting if the signal is expected to be valid , and is used
* to determine if the chip needs to be kept powered .
* - Changing both period and duty_cycle is not done atomically , neither is the
* multi - byte register updates , so the output might briefly be undefined
* during update .
*/
static int ti_sn_pwm_apply ( struct pwm_chip * chip , struct pwm_device * pwm ,
const struct pwm_state * state )
{
struct ti_sn65dsi86 * pdata = pwm_chip_to_ti_sn_bridge ( chip ) ;
unsigned int pwm_en_inv ;
unsigned int backlight ;
unsigned int pre_div ;
unsigned int scale ;
u64 period_max ;
u64 period ;
int ret ;
if ( ! pdata - > pwm_enabled ) {
ret = pm_runtime_get_sync ( pdata - > dev ) ;
if ( ret < 0 ) {
pm_runtime_put_sync ( pdata - > dev ) ;
return ret ;
}
}
if ( state - > enabled ) {
if ( ! pdata - > pwm_enabled ) {
/*
* The chip might have been powered down while we
* didn ' t hold a PM runtime reference , so mux in the
* PWM function on the GPIO pin again .
*/
ret = regmap_update_bits ( pdata - > regmap , SN_GPIO_CTRL_REG ,
SN_GPIO_MUX_MASK < < ( 2 * SN_PWM_GPIO_IDX ) ,
SN_GPIO_MUX_SPECIAL < < ( 2 * SN_PWM_GPIO_IDX ) ) ;
if ( ret ) {
dev_err ( pdata - > dev , " failed to mux in PWM function \n " ) ;
goto out ;
}
}
/*
* Per the datasheet the PWM frequency is given by :
*
* REFCLK_FREQ
* PWM_FREQ = - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* PWM_PRE_DIV * BACKLIGHT_SCALE + 1
*
* However , after careful review the author is convinced that
* the documentation has lost some parenthesis around
* " BACKLIGHT_SCALE + 1 " .
*
* With the period T_pwm = 1 / PWM_FREQ this can be written :
*
* T_pwm * REFCLK_FREQ = PWM_PRE_DIV * ( BACKLIGHT_SCALE + 1 )
*
* In order to keep BACKLIGHT_SCALE within its 16 bits ,
* PWM_PRE_DIV must be :
*
* T_pwm * REFCLK_FREQ
* PWM_PRE_DIV > = - - - - - - - - - - - - - - - - - - - - - - - - -
* BACKLIGHT_SCALE_MAX + 1
*
* To simplify the search and to favour higher resolution of
* the duty cycle over accuracy of the period , the lowest
* possible PWM_PRE_DIV is used . Finally the scale is
* calculated as :
*
* T_pwm * REFCLK_FREQ
* BACKLIGHT_SCALE = - - - - - - - - - - - - - - - - - - - - - - - 1
* PWM_PRE_DIV
*
* Here T_pwm is represented in seconds , so appropriate scaling
* to nanoseconds is necessary .
*/
/* Minimum T_pwm is 1 / REFCLK_FREQ */
if ( state - > period < = NSEC_PER_SEC / pdata - > pwm_refclk_freq ) {
ret = - EINVAL ;
goto out ;
}
/*
* Maximum T_pwm is 255 * ( 65535 + 1 ) / REFCLK_FREQ
* Limit period to this to avoid overflows
*/
period_max = div_u64 ( ( u64 ) NSEC_PER_SEC * 255 * ( 65535 + 1 ) ,
pdata - > pwm_refclk_freq ) ;
period = min ( state - > period , period_max ) ;
pre_div = DIV64_U64_ROUND_UP ( period * pdata - > pwm_refclk_freq ,
( u64 ) NSEC_PER_SEC * ( BACKLIGHT_SCALE_MAX + 1 ) ) ;
scale = div64_u64 ( period * pdata - > pwm_refclk_freq , ( u64 ) NSEC_PER_SEC * pre_div ) - 1 ;
/*
* The documentation has the duty ratio given as :
*
* duty BACKLIGHT
* - - - - - - - = - - - - - - - - - - - - - - - - - - - - -
* period BACKLIGHT_SCALE + 1
*
* Solve for BACKLIGHT , substituting BACKLIGHT_SCALE according
* to definition above and adjusting for nanosecond
* representation of duty cycle gives us :
*/
backlight = div64_u64 ( state - > duty_cycle * pdata - > pwm_refclk_freq ,
( u64 ) NSEC_PER_SEC * pre_div ) ;
if ( backlight > scale )
backlight = scale ;
ret = regmap_write ( pdata - > regmap , SN_PWM_PRE_DIV_REG , pre_div ) ;
if ( ret ) {
dev_err ( pdata - > dev , " failed to update PWM_PRE_DIV \n " ) ;
goto out ;
}
ti_sn65dsi86_write_u16 ( pdata , SN_BACKLIGHT_SCALE_REG , scale ) ;
ti_sn65dsi86_write_u16 ( pdata , SN_BACKLIGHT_REG , backlight ) ;
}
pwm_en_inv = FIELD_PREP ( SN_PWM_EN_MASK , state - > enabled ) |
FIELD_PREP ( SN_PWM_INV_MASK , state - > polarity = = PWM_POLARITY_INVERSED ) ;
ret = regmap_write ( pdata - > regmap , SN_PWM_EN_INV_REG , pwm_en_inv ) ;
if ( ret ) {
dev_err ( pdata - > dev , " failed to update PWM_EN/PWM_INV \n " ) ;
goto out ;
}
pdata - > pwm_enabled = state - > enabled ;
out :
if ( ! pdata - > pwm_enabled )
pm_runtime_put_sync ( pdata - > dev ) ;
return ret ;
}
static void ti_sn_pwm_get_state ( struct pwm_chip * chip , struct pwm_device * pwm ,
struct pwm_state * state )
{
struct ti_sn65dsi86 * pdata = pwm_chip_to_ti_sn_bridge ( chip ) ;
unsigned int pwm_en_inv ;
unsigned int pre_div ;
u16 backlight ;
u16 scale ;
int ret ;
ret = regmap_read ( pdata - > regmap , SN_PWM_EN_INV_REG , & pwm_en_inv ) ;
if ( ret )
return ;
ret = ti_sn65dsi86_read_u16 ( pdata , SN_BACKLIGHT_SCALE_REG , & scale ) ;
if ( ret )
return ;
ret = ti_sn65dsi86_read_u16 ( pdata , SN_BACKLIGHT_REG , & backlight ) ;
if ( ret )
return ;
ret = regmap_read ( pdata - > regmap , SN_PWM_PRE_DIV_REG , & pre_div ) ;
if ( ret )
return ;
state - > enabled = FIELD_GET ( SN_PWM_EN_MASK , pwm_en_inv ) ;
if ( FIELD_GET ( SN_PWM_INV_MASK , pwm_en_inv ) )
state - > polarity = PWM_POLARITY_INVERSED ;
else
state - > polarity = PWM_POLARITY_NORMAL ;
state - > period = DIV_ROUND_UP_ULL ( ( u64 ) NSEC_PER_SEC * pre_div * ( scale + 1 ) ,
pdata - > pwm_refclk_freq ) ;
state - > duty_cycle = DIV_ROUND_UP_ULL ( ( u64 ) NSEC_PER_SEC * pre_div * backlight ,
pdata - > pwm_refclk_freq ) ;
if ( state - > duty_cycle > state - > period )
state - > duty_cycle = state - > period ;
}
static const struct pwm_ops ti_sn_pwm_ops = {
. request = ti_sn_pwm_request ,
. free = ti_sn_pwm_free ,
. apply = ti_sn_pwm_apply ,
. get_state = ti_sn_pwm_get_state ,
. owner = THIS_MODULE ,
} ;
static int ti_sn_pwm_probe ( struct auxiliary_device * adev ,
const struct auxiliary_device_id * id )
{
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( adev - > dev . parent ) ;
pdata - > pchip . dev = pdata - > dev ;
pdata - > pchip . ops = & ti_sn_pwm_ops ;
pdata - > pchip . npwm = 1 ;
pdata - > pchip . of_xlate = of_pwm_single_xlate ;
pdata - > pchip . of_pwm_n_cells = 1 ;
return pwmchip_add ( & pdata - > pchip ) ;
}
static void ti_sn_pwm_remove ( struct auxiliary_device * adev )
{
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( adev - > dev . parent ) ;
pwmchip_remove ( & pdata - > pchip ) ;
if ( pdata - > pwm_enabled )
pm_runtime_put_sync ( pdata - > dev ) ;
}
static const struct auxiliary_device_id ti_sn_pwm_id_table [ ] = {
{ . name = " ti_sn65dsi86.pwm " , } ,
{ } ,
} ;
static struct auxiliary_driver ti_sn_pwm_driver = {
. name = " pwm " ,
. probe = ti_sn_pwm_probe ,
. remove = ti_sn_pwm_remove ,
. id_table = ti_sn_pwm_id_table ,
} ;
static int __init ti_sn_pwm_register ( void )
{
return auxiliary_driver_register ( & ti_sn_pwm_driver ) ;
}
static void ti_sn_pwm_unregister ( void )
{
auxiliary_driver_unregister ( & ti_sn_pwm_driver ) ;
}
# else
static inline int ti_sn_pwm_pin_request ( struct ti_sn65dsi86 * pdata ) { return 0 ; }
static inline void ti_sn_pwm_pin_release ( struct ti_sn65dsi86 * pdata ) { }
static inline int ti_sn_pwm_register ( void ) { return 0 ; }
static inline void ti_sn_pwm_unregister ( void ) { }
# endif
/* -----------------------------------------------------------------------------
* GPIO Controller
*/
2020-06-12 12:30:47 -07:00
# if defined(CONFIG_OF_GPIO)
2020-05-07 14:34:55 -07:00
static int tn_sn_bridge_of_xlate ( struct gpio_chip * chip ,
const struct of_phandle_args * gpiospec ,
u32 * flags )
{
if ( WARN_ON ( gpiospec - > args_count < chip - > of_gpio_n_cells ) )
return - EINVAL ;
if ( gpiospec - > args [ 0 ] > chip - > ngpio | | gpiospec - > args [ 0 ] < 1 )
return - EINVAL ;
if ( flags )
* flags = gpiospec - > args [ 1 ] ;
return gpiospec - > args [ 0 ] - SN_GPIO_PHYSICAL_OFFSET ;
}
static int ti_sn_bridge_gpio_get_direction ( struct gpio_chip * chip ,
unsigned int offset )
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
2020-05-07 14:34:55 -07:00
/*
* We already have to keep track of the direction because we use
* that to figure out whether we ' ve powered the device . We can
* just return that rather than ( maybe ) powering up the device
* to ask its direction .
*/
return test_bit ( offset , pdata - > gchip_output ) ?
GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN ;
}
static int ti_sn_bridge_gpio_get ( struct gpio_chip * chip , unsigned int offset )
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
2020-05-07 14:34:55 -07:00
unsigned int val ;
int ret ;
/*
* When the pin is an input we don ' t forcibly keep the bridge
* powered - - we just power it on to read the pin . NOTE : part of
* the reason this works is that the bridge defaults ( when
* powered back on ) to all 4 GPIOs being configured as GPIO input .
* Also note that if something else is keeping the chip powered the
* pm_runtime functions are lightweight increments of a refcount .
*/
pm_runtime_get_sync ( pdata - > dev ) ;
ret = regmap_read ( pdata - > regmap , SN_GPIO_IO_REG , & val ) ;
2021-04-23 09:58:57 -07:00
pm_runtime_put_autosuspend ( pdata - > dev ) ;
2020-05-07 14:34:55 -07:00
if ( ret )
return ret ;
return ! ! ( val & BIT ( SN_GPIO_INPUT_SHIFT + offset ) ) ;
}
static void ti_sn_bridge_gpio_set ( struct gpio_chip * chip , unsigned int offset ,
int val )
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
2020-05-07 14:34:55 -07:00
int ret ;
if ( ! test_bit ( offset , pdata - > gchip_output ) ) {
dev_err ( pdata - > dev , " Ignoring GPIO set while input \n " ) ;
return ;
}
val & = 1 ;
ret = regmap_update_bits ( pdata - > regmap , SN_GPIO_IO_REG ,
BIT ( SN_GPIO_OUTPUT_SHIFT + offset ) ,
val < < ( SN_GPIO_OUTPUT_SHIFT + offset ) ) ;
2020-06-12 12:30:50 -07:00
if ( ret )
dev_warn ( pdata - > dev ,
" Failed to set bridge GPIO %u: %d \n " , offset , ret ) ;
2020-05-07 14:34:55 -07:00
}
static int ti_sn_bridge_gpio_direction_input ( struct gpio_chip * chip ,
unsigned int offset )
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
2020-05-07 14:34:55 -07:00
int shift = offset * 2 ;
int ret ;
if ( ! test_and_clear_bit ( offset , pdata - > gchip_output ) )
return 0 ;
ret = regmap_update_bits ( pdata - > regmap , SN_GPIO_CTRL_REG ,
SN_GPIO_MUX_MASK < < shift ,
SN_GPIO_MUX_INPUT < < shift ) ;
if ( ret ) {
set_bit ( offset , pdata - > gchip_output ) ;
return ret ;
}
/*
* NOTE : if nobody else is powering the device this may fully power
* it off and when it comes back it will have lost all state , but
* that ' s OK because the default is input and we ' re now an input .
*/
2021-04-23 09:58:57 -07:00
pm_runtime_put_autosuspend ( pdata - > dev ) ;
2020-05-07 14:34:55 -07:00
return 0 ;
}
static int ti_sn_bridge_gpio_direction_output ( struct gpio_chip * chip ,
unsigned int offset , int val )
{
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
2020-05-07 14:34:55 -07:00
int shift = offset * 2 ;
int ret ;
if ( test_and_set_bit ( offset , pdata - > gchip_output ) )
return 0 ;
pm_runtime_get_sync ( pdata - > dev ) ;
/* Set value first to avoid glitching */
ti_sn_bridge_gpio_set ( chip , offset , val ) ;
/* Set direction */
ret = regmap_update_bits ( pdata - > regmap , SN_GPIO_CTRL_REG ,
SN_GPIO_MUX_MASK < < shift ,
SN_GPIO_MUX_OUTPUT < < shift ) ;
if ( ret ) {
clear_bit ( offset , pdata - > gchip_output ) ;
2021-04-23 09:58:57 -07:00
pm_runtime_put_autosuspend ( pdata - > dev ) ;
2020-05-07 14:34:55 -07:00
}
return ret ;
}
2021-10-25 10:09:25 -07:00
static int ti_sn_bridge_gpio_request ( struct gpio_chip * chip , unsigned int offset )
{
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
if ( offset = = SN_PWM_GPIO_IDX )
return ti_sn_pwm_pin_request ( pdata ) ;
return 0 ;
}
2020-05-07 14:34:55 -07:00
static void ti_sn_bridge_gpio_free ( struct gpio_chip * chip , unsigned int offset )
{
2021-10-25 10:09:25 -07:00
struct ti_sn65dsi86 * pdata = gpiochip_get_data ( chip ) ;
2020-05-07 14:34:55 -07:00
/* We won't keep pm_runtime if we're input, so switch there on free */
ti_sn_bridge_gpio_direction_input ( chip , offset ) ;
2021-10-25 10:09:25 -07:00
if ( offset = = SN_PWM_GPIO_IDX )
ti_sn_pwm_pin_release ( pdata ) ;
2020-05-07 14:34:55 -07:00
}
static const char * const ti_sn_bridge_gpio_names [ SN_NUM_GPIOS ] = {
" GPIO1 " , " GPIO2 " , " GPIO3 " , " GPIO4 "
} ;
2021-04-23 09:58:55 -07:00
static int ti_sn_gpio_probe ( struct auxiliary_device * adev ,
const struct auxiliary_device_id * id )
2020-05-07 14:34:55 -07:00
{
2021-04-23 09:58:55 -07:00
struct ti_sn65dsi86 * pdata = dev_get_drvdata ( adev - > dev . parent ) ;
2020-05-07 14:34:55 -07:00
int ret ;
/* Only init if someone is going to use us as a GPIO controller */
if ( ! of_property_read_bool ( pdata - > dev - > of_node , " gpio-controller " ) )
return 0 ;
pdata - > gchip . label = dev_name ( pdata - > dev ) ;
pdata - > gchip . parent = pdata - > dev ;
pdata - > gchip . owner = THIS_MODULE ;
pdata - > gchip . of_xlate = tn_sn_bridge_of_xlate ;
pdata - > gchip . of_gpio_n_cells = 2 ;
2021-10-25 10:09:25 -07:00
pdata - > gchip . request = ti_sn_bridge_gpio_request ;
2020-05-07 14:34:55 -07:00
pdata - > gchip . free = ti_sn_bridge_gpio_free ;
pdata - > gchip . get_direction = ti_sn_bridge_gpio_get_direction ;
pdata - > gchip . direction_input = ti_sn_bridge_gpio_direction_input ;
pdata - > gchip . direction_output = ti_sn_bridge_gpio_direction_output ;
pdata - > gchip . get = ti_sn_bridge_gpio_get ;
pdata - > gchip . set = ti_sn_bridge_gpio_set ;
pdata - > gchip . can_sleep = true ;
pdata - > gchip . names = ti_sn_bridge_gpio_names ;
pdata - > gchip . ngpio = SN_NUM_GPIOS ;
pdata - > gchip . base = - 1 ;
2021-04-23 09:58:55 -07:00
ret = devm_gpiochip_add_data ( & adev - > dev , & pdata - > gchip , pdata ) ;
2020-05-07 14:34:55 -07:00
if ( ret )
dev_err ( pdata - > dev , " can't add gpio chip \n " ) ;
return ret ;
}
2021-04-23 09:58:55 -07:00
static const struct auxiliary_device_id ti_sn_gpio_id_table [ ] = {
{ . name = " ti_sn65dsi86.gpio " , } ,
{ } ,
} ;
2020-06-12 12:30:47 -07:00
2021-04-23 09:58:55 -07:00
MODULE_DEVICE_TABLE ( auxiliary , ti_sn_gpio_id_table ) ;
static struct auxiliary_driver ti_sn_gpio_driver = {
. name = " gpio " ,
. probe = ti_sn_gpio_probe ,
. id_table = ti_sn_gpio_id_table ,
} ;
static int __init ti_sn_gpio_register ( void )
2020-06-12 12:30:47 -07:00
{
2021-04-23 09:58:55 -07:00
return auxiliary_driver_register ( & ti_sn_gpio_driver ) ;
2020-06-12 12:30:47 -07:00
}
2021-05-04 07:38:54 -07:00
static void ti_sn_gpio_unregister ( void )
2021-04-23 09:58:55 -07:00
{
auxiliary_driver_unregister ( & ti_sn_gpio_driver ) ;
}
# else
static inline int ti_sn_gpio_register ( void ) { return 0 ; }
static inline void ti_sn_gpio_unregister ( void ) { }
2020-06-12 12:30:47 -07:00
# endif
2021-06-24 03:03:03 +03:00
/* -----------------------------------------------------------------------------
* Probe & Remove
*/
2021-04-23 09:58:55 -07:00
2021-04-23 09:58:50 -07:00
static void ti_sn65dsi86_runtime_disable ( void * data )
{
2022-02-22 14:18:43 -08:00
pm_runtime_dont_use_autosuspend ( data ) ;
2021-04-23 09:58:50 -07:00
pm_runtime_disable ( data ) ;
}
2021-06-24 03:03:03 +03:00
static int ti_sn65dsi86_parse_regulators ( struct ti_sn65dsi86 * pdata )
2021-06-11 10:17:43 -07:00
{
2021-06-24 03:03:03 +03:00
unsigned int i ;
const char * const ti_sn_bridge_supply_names [ ] = {
" vcca " , " vcc " , " vccio " , " vpll " ,
} ;
2021-06-11 10:17:43 -07:00
2021-06-24 03:03:03 +03:00
for ( i = 0 ; i < SN_REGULATOR_SUPPLY_NUM ; i + + )
pdata - > supplies [ i ] . supply = ti_sn_bridge_supply_names [ i ] ;
2021-06-11 10:17:44 -07:00
2021-06-24 03:03:03 +03:00
return devm_regulator_bulk_get ( pdata - > dev , SN_REGULATOR_SUPPLY_NUM ,
pdata - > supplies ) ;
2021-06-11 10:17:43 -07:00
}
2021-04-23 09:58:49 -07:00
static int ti_sn65dsi86_probe ( struct i2c_client * client ,
2018-07-20 12:24:02 +05:30
const struct i2c_device_id * id )
{
2021-04-23 09:58:52 -07:00
struct device * dev = & client - > dev ;
2021-04-23 09:58:48 -07:00
struct ti_sn65dsi86 * pdata ;
2018-07-20 12:24:02 +05:30
int ret ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
DRM_ERROR ( " device doesn't support I2C \n " ) ;
return - ENODEV ;
}
2021-04-23 09:58:52 -07:00
pdata = devm_kzalloc ( dev , sizeof ( struct ti_sn65dsi86 ) , GFP_KERNEL ) ;
2018-07-20 12:24:02 +05:30
if ( ! pdata )
return - ENOMEM ;
2021-04-23 09:58:53 -07:00
dev_set_drvdata ( dev , pdata ) ;
pdata - > dev = dev ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:59 -07:00
mutex_init ( & pdata - > comms_mutex ) ;
2018-07-20 12:24:02 +05:30
pdata - > regmap = devm_regmap_init_i2c ( client ,
2021-04-23 09:58:49 -07:00
& ti_sn65dsi86_regmap_config ) ;
2021-06-11 10:17:46 -07:00
if ( IS_ERR ( pdata - > regmap ) )
return dev_err_probe ( dev , PTR_ERR ( pdata - > regmap ) ,
" regmap i2c init failed \n " ) ;
2018-07-20 12:24:02 +05:30
2021-06-24 03:03:00 +03:00
pdata - > enable_gpio = devm_gpiod_get_optional ( dev , " enable " ,
GPIOD_OUT_LOW ) ;
2021-06-11 10:17:46 -07:00
if ( IS_ERR ( pdata - > enable_gpio ) )
return dev_err_probe ( dev , PTR_ERR ( pdata - > enable_gpio ) ,
" failed to get enable gpio from DT \n " ) ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:49 -07:00
ret = ti_sn65dsi86_parse_regulators ( pdata ) ;
2021-06-11 10:17:46 -07:00
if ( ret )
return dev_err_probe ( dev , ret , " failed to parse regulators \n " ) ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:52 -07:00
pdata - > refclk = devm_clk_get_optional ( dev , " refclk " ) ;
2021-04-16 15:39:25 -07:00
if ( IS_ERR ( pdata - > refclk ) )
2021-06-11 10:17:46 -07:00
return dev_err_probe ( dev , PTR_ERR ( pdata - > refclk ) ,
" failed to get reference clock \n " ) ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:54 -07:00
pm_runtime_enable ( dev ) ;
2022-02-22 14:18:43 -08:00
pm_runtime_set_autosuspend_delay ( pdata - > dev , 500 ) ;
pm_runtime_use_autosuspend ( pdata - > dev ) ;
2021-04-23 09:58:54 -07:00
ret = devm_add_action_or_reset ( dev , ti_sn65dsi86_runtime_disable , dev ) ;
2018-07-20 12:24:02 +05:30
if ( ret )
return ret ;
2021-04-23 09:58:54 -07:00
ti_sn65dsi86_debugfs_init ( pdata ) ;
2021-04-23 09:58:55 -07:00
/*
* Break ourselves up into a collection of aux devices . The only real
* motiviation here is to solve the chicken - and - egg problem of probe
* ordering . The bridge wants the panel to be there when it probes .
* The panel wants its HPD GPIO ( provided by sn65dsi86 on some boards )
2021-06-11 10:17:43 -07:00
* when it probes . The panel and maybe backlight might want the DDC
2021-10-25 10:09:25 -07:00
* bus or the pwm_chip . Having sub - devices allows the some sub devices
* to finish probing even if others return - EPROBE_DEFER and gets us
* around the problems .
2021-04-23 09:58:55 -07:00
*/
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:55 -07:00
if ( IS_ENABLED ( CONFIG_OF_GPIO ) ) {
ret = ti_sn65dsi86_add_aux_device ( pdata , & pdata - > gpio_aux , " gpio " ) ;
if ( ret )
return ret ;
2018-07-20 12:24:02 +05:30
}
2021-10-25 10:09:25 -07:00
if ( IS_ENABLED ( CONFIG_PWM ) ) {
ret = ti_sn65dsi86_add_aux_device ( pdata , & pdata - > pwm_aux , " pwm " ) ;
if ( ret )
return ret ;
}
2021-06-11 10:17:43 -07:00
/*
* NOTE : At the end of the AUX channel probe we ' ll add the aux device
* for the bridge . This is because the bridge can ' t be used until the
* AUX channel is there and this is a very simple solution to the
* dependency problem .
*/
return ti_sn65dsi86_add_aux_device ( pdata , & pdata - > aux_aux , " aux " ) ;
2018-07-20 12:24:02 +05:30
}
2021-04-23 09:58:49 -07:00
static struct i2c_device_id ti_sn65dsi86_id [ ] = {
2018-07-20 12:24:02 +05:30
{ " ti,sn65dsi86 " , 0 } ,
{ } ,
} ;
2021-04-23 09:58:49 -07:00
MODULE_DEVICE_TABLE ( i2c , ti_sn65dsi86_id ) ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:49 -07:00
static const struct of_device_id ti_sn65dsi86_match_table [ ] = {
2018-07-20 12:24:02 +05:30
{ . compatible = " ti,sn65dsi86 " } ,
{ } ,
} ;
2021-04-23 09:58:49 -07:00
MODULE_DEVICE_TABLE ( of , ti_sn65dsi86_match_table ) ;
2018-07-20 12:24:02 +05:30
2021-04-23 09:58:49 -07:00
static struct i2c_driver ti_sn65dsi86_driver = {
2018-07-20 12:24:02 +05:30
. driver = {
. name = " ti_sn65dsi86 " ,
2021-04-23 09:58:49 -07:00
. of_match_table = ti_sn65dsi86_match_table ,
. pm = & ti_sn65dsi86_pm_ops ,
2018-07-20 12:24:02 +05:30
} ,
2021-04-23 09:58:49 -07:00
. probe = ti_sn65dsi86_probe ,
. id_table = ti_sn65dsi86_id ,
2018-07-20 12:24:02 +05:30
} ;
2021-04-23 09:58:55 -07:00
static int __init ti_sn65dsi86_init ( void )
{
int ret ;
ret = i2c_add_driver ( & ti_sn65dsi86_driver ) ;
if ( ret )
return ret ;
ret = ti_sn_gpio_register ( ) ;
if ( ret )
goto err_main_was_registered ;
2021-10-25 10:09:25 -07:00
ret = ti_sn_pwm_register ( ) ;
2021-04-23 09:58:55 -07:00
if ( ret )
goto err_gpio_was_registered ;
2021-10-25 10:09:25 -07:00
ret = auxiliary_driver_register ( & ti_sn_aux_driver ) ;
if ( ret )
goto err_pwm_was_registered ;
2021-06-11 10:17:43 -07:00
ret = auxiliary_driver_register ( & ti_sn_bridge_driver ) ;
if ( ret )
goto err_aux_was_registered ;
2021-04-23 09:58:55 -07:00
return 0 ;
2021-06-11 10:17:43 -07:00
err_aux_was_registered :
auxiliary_driver_unregister ( & ti_sn_aux_driver ) ;
2021-10-25 10:09:25 -07:00
err_pwm_was_registered :
ti_sn_pwm_unregister ( ) ;
2021-04-23 09:58:55 -07:00
err_gpio_was_registered :
ti_sn_gpio_unregister ( ) ;
err_main_was_registered :
i2c_del_driver ( & ti_sn65dsi86_driver ) ;
return ret ;
}
module_init ( ti_sn65dsi86_init ) ;
static void __exit ti_sn65dsi86_exit ( void )
{
auxiliary_driver_unregister ( & ti_sn_bridge_driver ) ;
2021-06-11 10:17:43 -07:00
auxiliary_driver_unregister ( & ti_sn_aux_driver ) ;
2021-10-25 10:09:25 -07:00
ti_sn_pwm_unregister ( ) ;
2021-04-23 09:58:55 -07:00
ti_sn_gpio_unregister ( ) ;
i2c_del_driver ( & ti_sn65dsi86_driver ) ;
}
module_exit ( ti_sn65dsi86_exit ) ;
2018-07-20 12:24:02 +05:30
MODULE_AUTHOR ( " Sandeep Panda <spanda@codeaurora.org> " ) ;
MODULE_DESCRIPTION ( " sn65dsi86 DSI to eDP bridge driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;