To answer your question, you are querying for the list where it matches a sub-element and that will only happen where the list is comprised of one element.  What you really wanted to select are the sub-elements themselves.
Note: Explanation of why parsing strings using the regex form '[^_]+' is bad here: https://stackoverflow.com/a/31464699/2543416
You want to parse the list, selecting the elements:
SQL> with TVL_DETAIL(TVL_CD_LIST) as (
     select 'M1180_Z6827' from dual union
     select 'K5900_Z6828' from dual union
     select 'I2510' from dual
   )
   SELECT distinct regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, level, NULL, 1) element
   FROM TVL_DETAIL
   CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1;
   -- 11g  CONNECT BY level <= regexp_count(TVL_CD_LIST, '_') + 1;
ELEMENT
-----------
Z6827
K5900
M1180
I2510
Z6828
SQL>
And this is cool if you want to track by row and element within row:
SQL> with TVL_DETAIL(row_nbr, TVL_CD_LIST) as (
     select 1, 'M1180_Z6827' from dual union
     select 2, 'K5900_Z6828' from dual union
     select 3, 'I2510' from dual
   )
   SELECT row_nbr, column_value substring_nbr,
          regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, column_value, NULL, 1) element
   FROM TVL_DETAIL,
     TABLE(
       CAST(
         MULTISET(SELECT LEVEL
                  FROM dual
                  CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1
                  -- 11g CONNECT BY LEVEL <= REGEXP_COUNT(TVL_CD_LIST, '_')+1
                  ) AS sys.OdciNumberList
           )
     )
   order by row_nbr, substring_nbr;
   ROW_NBR SUBSTRING_NBR ELEMENT
---------- ------------- -----------
         1             1 M1180
         1             2 Z6827
         2             1 K5900
         2             2 Z6828
         3             1 I2510
SQL>
EDIT:  Oops, edited to work with 10g as REGEXP_COUNT is not available until 11g.